@walkthru-earth/objex 1.3.1 → 1.5.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.
Files changed (199) hide show
  1. package/LICENSE +5 -0
  2. package/README.md +28 -20
  3. package/dist/components/browser/FileTreeSidebar.svelte +32 -17
  4. package/dist/components/layout/AboutSheet.svelte +5 -2
  5. package/dist/components/layout/ConnectionDialog.svelte +7 -2
  6. package/dist/components/layout/SettingsSheet.svelte +238 -0
  7. package/dist/components/layout/SettingsSheet.svelte.d.ts +6 -0
  8. package/dist/components/layout/Sidebar.svelte +73 -6
  9. package/dist/components/layout/Sidebar.svelte.d.ts +4 -1
  10. package/dist/components/layout/StatusBar.svelte +17 -14
  11. package/dist/components/layout/TabBar.svelte +4 -4
  12. package/dist/components/ui/context-menu/context-menu-radio-group.svelte.d.ts +1 -1
  13. package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte.d.ts +1 -1
  14. package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +1 -1
  15. package/dist/components/ui/input/input.svelte.d.ts +1 -1
  16. package/dist/components/ui/resizable/index.d.ts +1 -1
  17. package/dist/components/ui/resizable/index.js +2 -2
  18. package/dist/components/ui/slider/index.d.ts +3 -0
  19. package/dist/components/ui/slider/index.js +5 -0
  20. package/dist/components/ui/slider/range-slider.svelte +94 -0
  21. package/dist/components/ui/slider/range-slider.svelte.d.ts +21 -0
  22. package/dist/components/ui/slider/slider.svelte +83 -0
  23. package/dist/components/ui/slider/slider.svelte.d.ts +7 -0
  24. package/dist/components/viewers/ArchiveViewer.svelte +140 -113
  25. package/dist/components/viewers/CodeViewer.svelte +45 -48
  26. package/dist/components/viewers/CodeViewer.svelte.d.ts +1 -1
  27. package/dist/components/viewers/CogControls.svelte +338 -184
  28. package/dist/components/viewers/CogControls.svelte.d.ts +33 -10
  29. package/dist/components/viewers/CogViewer.svelte +269 -116
  30. package/dist/components/viewers/CopcViewer.svelte +8 -15
  31. package/dist/components/viewers/DatabaseViewer.svelte +22 -21
  32. package/dist/components/viewers/FileInfo.svelte +16 -16
  33. package/dist/components/viewers/FlatGeobufViewer.svelte +16 -46
  34. package/dist/components/viewers/GeoParquetMapViewer.svelte +11 -9
  35. package/dist/components/viewers/GeoParquetMapViewer.svelte.d.ts +1 -1
  36. package/dist/components/viewers/ImageViewer.svelte +12 -14
  37. package/dist/components/viewers/LoadProgress.svelte +6 -6
  38. package/dist/components/viewers/MarkdownViewer.svelte +29 -30
  39. package/dist/components/viewers/MediaViewer.svelte +13 -14
  40. package/dist/components/viewers/ModelViewer.svelte +18 -21
  41. package/dist/components/viewers/MultiCogViewer.svelte +474 -106
  42. package/dist/components/viewers/MultiCogViewer.svelte.d.ts +1 -1
  43. package/dist/components/viewers/NotebookViewer.svelte +28 -29
  44. package/dist/components/viewers/PdfViewer.svelte +24 -33
  45. package/dist/components/viewers/PmtilesViewer.svelte +13 -15
  46. package/dist/components/viewers/QueryHistoryPanel.svelte +18 -18
  47. package/dist/components/viewers/RawViewer.svelte +27 -21
  48. package/dist/components/viewers/StacMapViewer.svelte +6 -13
  49. package/dist/components/viewers/StacMosaicViewer.svelte +1764 -410
  50. package/dist/components/viewers/StacMosaicViewer.svelte.d.ts +1 -1
  51. package/dist/components/viewers/StacTabViewer.svelte +26 -15
  52. package/dist/components/viewers/StacTabViewer.svelte.d.ts +1 -1
  53. package/dist/components/viewers/TableGrid.svelte +38 -34
  54. package/dist/components/viewers/TableStatusBar.svelte +7 -7
  55. package/dist/components/viewers/TableToolbar.svelte +10 -9
  56. package/dist/components/viewers/TableViewer.svelte +47 -30
  57. package/dist/components/viewers/TableViewer.svelte.d.ts +1 -0
  58. package/dist/components/viewers/ViewerHeader.svelte +18 -0
  59. package/dist/components/viewers/ViewerHeader.svelte.d.ts +10 -0
  60. package/dist/components/viewers/ViewerRouter.svelte +16 -8
  61. package/dist/components/viewers/ViewerStatus.svelte +19 -0
  62. package/dist/components/viewers/ViewerStatus.svelte.d.ts +7 -0
  63. package/dist/components/viewers/ZarrMapViewer.svelte +24 -21
  64. package/dist/components/viewers/ZarrViewer.svelte +98 -65
  65. package/dist/components/viewers/cog/ChannelPicker.svelte +83 -0
  66. package/dist/components/viewers/cog/ChannelPicker.svelte.d.ts +13 -0
  67. package/dist/components/viewers/cog/PixelInspectorPanel.svelte +87 -0
  68. package/dist/components/viewers/cog/PixelInspectorPanel.svelte.d.ts +17 -0
  69. package/dist/components/viewers/cog/buildRgbLayer.d.ts +78 -0
  70. package/dist/components/viewers/cog/buildRgbLayer.js +176 -0
  71. package/dist/components/viewers/map/AttributeTable.svelte +7 -7
  72. package/dist/components/viewers/map/MapContainer.svelte +38 -12
  73. package/dist/components/viewers/pmtiles/PmtilesArchiveView.svelte +109 -83
  74. package/dist/components/viewers/pmtiles/PmtilesTileInspector.svelte +16 -16
  75. package/dist/components/viewers/stac/StacDatetimeBar.svelte +175 -0
  76. package/dist/components/viewers/stac/StacDatetimeBar.svelte.d.ts +10 -0
  77. package/dist/components/viewers/stac/StacFilterPanel.svelte +243 -0
  78. package/dist/components/viewers/stac/StacFilterPanel.svelte.d.ts +14 -0
  79. package/dist/components/viewers/stac/StacItemInspector.svelte +223 -0
  80. package/dist/components/viewers/stac/StacItemInspector.svelte.d.ts +10 -0
  81. package/dist/components/viewers/stac/StacItemStrip.svelte +228 -0
  82. package/dist/components/viewers/stac/StacItemStrip.svelte.d.ts +12 -0
  83. package/dist/constants.d.ts +6 -0
  84. package/dist/constants.js +8 -0
  85. package/dist/file-icons/index.d.ts +1 -1
  86. package/dist/file-icons/index.js +1 -1
  87. package/dist/i18n/ar.js +113 -2
  88. package/dist/i18n/en.js +113 -2
  89. package/dist/index.d.ts +2 -28
  90. package/dist/index.js +7 -23
  91. package/dist/query/engine.d.ts +10 -0
  92. package/dist/query/source.js +1 -1
  93. package/dist/query/stac-source-factory.d.ts +65 -0
  94. package/dist/query/stac-source-factory.js +77 -0
  95. package/dist/query/stac-source-parquet.d.ts +135 -0
  96. package/dist/query/stac-source-parquet.js +468 -0
  97. package/dist/query/wasm.d.ts +8 -0
  98. package/dist/query/wasm.js +310 -65
  99. package/dist/storage/presign.js +3 -2
  100. package/dist/storage/providers.js +7 -6
  101. package/dist/stores/config.svelte.d.ts +15 -0
  102. package/dist/stores/config.svelte.js +46 -0
  103. package/dist/stores/connections.svelte.d.ts +2 -2
  104. package/dist/stores/connections.svelte.js +1 -2
  105. package/dist/stores/files.svelte.d.ts +1 -1
  106. package/dist/stores/files.svelte.js +1 -1
  107. package/dist/stores/query-history.svelte.js +1 -1
  108. package/dist/stores/settings.svelte.d.ts +16 -1
  109. package/dist/stores/settings.svelte.js +104 -48
  110. package/dist/stores/tabs.svelte.d.ts +3 -0
  111. package/dist/stores/tabs.svelte.js +17 -0
  112. package/dist/utils/cog-histogram.d.ts +121 -0
  113. package/dist/utils/cog-histogram.js +424 -0
  114. package/dist/utils/cog.d.ts +177 -20
  115. package/dist/utils/cog.js +361 -76
  116. package/dist/utils/colormap-sprite.d.ts +0 -9
  117. package/dist/utils/colormap-sprite.js +0 -21
  118. package/dist/utils/deck.d.ts +18 -12
  119. package/dist/utils/deck.js +15 -7
  120. package/dist/utils/media-query.svelte.d.ts +14 -0
  121. package/dist/utils/media-query.svelte.js +29 -0
  122. package/dist/utils/pmtiles-tile.js +2 -2
  123. package/dist/utils/signed-url-effect.d.ts +7 -0
  124. package/dist/utils/signed-url-effect.js +19 -0
  125. package/dist/utils/{url.d.ts → signed-url.d.ts} +15 -1
  126. package/dist/utils/{url.js → signed-url.js} +32 -10
  127. package/dist/utils/url-state.d.ts +36 -0
  128. package/dist/utils/url-state.js +72 -2
  129. package/dist/utils/zarr-tab.d.ts +1 -2
  130. package/dist/utils/zarr-tab.js +1 -2
  131. package/dist/utils/zarr.d.ts +0 -17
  132. package/dist/utils/zarr.js +1 -45
  133. package/package.json +55 -84
  134. package/dist/components/browser/Breadcrumb.svelte +0 -50
  135. package/dist/components/browser/Breadcrumb.svelte.d.ts +0 -7
  136. package/dist/components/browser/CreateFolderDialog.svelte +0 -98
  137. package/dist/components/browser/CreateFolderDialog.svelte.d.ts +0 -6
  138. package/dist/components/browser/DeleteConfirmDialog.svelte +0 -90
  139. package/dist/components/browser/DeleteConfirmDialog.svelte.d.ts +0 -8
  140. package/dist/components/browser/DropZone.svelte +0 -83
  141. package/dist/components/browser/DropZone.svelte.d.ts +0 -7
  142. package/dist/components/browser/FileBrowser.svelte +0 -252
  143. package/dist/components/browser/FileBrowser.svelte.d.ts +0 -3
  144. package/dist/components/browser/FileRow.svelte +0 -117
  145. package/dist/components/browser/FileRow.svelte.d.ts +0 -9
  146. package/dist/components/browser/RenameDialog.svelte +0 -101
  147. package/dist/components/browser/RenameDialog.svelte.d.ts +0 -8
  148. package/dist/components/browser/SearchBar.svelte +0 -40
  149. package/dist/components/browser/SearchBar.svelte.d.ts +0 -6
  150. package/dist/components/browser/UploadButton.svelte +0 -65
  151. package/dist/components/browser/UploadButton.svelte.d.ts +0 -3
  152. package/dist/query/stac-geoparquet.d.ts +0 -31
  153. package/dist/query/stac-geoparquet.js +0 -136
  154. package/dist/utils/clipboard.d.ts +0 -13
  155. package/dist/utils/clipboard.js +0 -38
  156. package/dist/utils/cloud-url.d.ts +0 -27
  157. package/dist/utils/cloud-url.js +0 -61
  158. package/dist/utils/cog-pure.d.ts +0 -25
  159. package/dist/utils/cog-pure.js +0 -35
  160. package/dist/utils/column-types.d.ts +0 -5
  161. package/dist/utils/column-types.js +0 -137
  162. package/dist/utils/connection-identity.d.ts +0 -51
  163. package/dist/utils/connection-identity.js +0 -97
  164. package/dist/utils/error.d.ts +0 -8
  165. package/dist/utils/error.js +0 -12
  166. package/dist/utils/evidence-context.d.ts +0 -22
  167. package/dist/utils/evidence-context.js +0 -56
  168. package/dist/utils/export.d.ts +0 -22
  169. package/dist/utils/export.js +0 -76
  170. package/dist/utils/file-sort.d.ts +0 -20
  171. package/dist/utils/file-sort.js +0 -41
  172. package/dist/utils/format.d.ts +0 -24
  173. package/dist/utils/format.js +0 -78
  174. package/dist/utils/geoarrow.d.ts +0 -32
  175. package/dist/utils/geoarrow.js +0 -672
  176. package/dist/utils/geometry-type.d.ts +0 -52
  177. package/dist/utils/geometry-type.js +0 -76
  178. package/dist/utils/hex.d.ts +0 -10
  179. package/dist/utils/hex.js +0 -27
  180. package/dist/utils/host-detection.d.ts +0 -23
  181. package/dist/utils/host-detection.js +0 -95
  182. package/dist/utils/local-storage.d.ts +0 -16
  183. package/dist/utils/local-storage.js +0 -37
  184. package/dist/utils/markdown-sql.d.ts +0 -30
  185. package/dist/utils/markdown-sql.js +0 -72
  186. package/dist/utils/notebook.d.ts +0 -59
  187. package/dist/utils/notebook.js +0 -211
  188. package/dist/utils/parquet-metadata.d.ts +0 -64
  189. package/dist/utils/parquet-metadata.js +0 -262
  190. package/dist/utils/stac-geoparquet.d.ts +0 -90
  191. package/dist/utils/stac-geoparquet.js +0 -223
  192. package/dist/utils/stac-hydrate.d.ts +0 -38
  193. package/dist/utils/stac-hydrate.js +0 -243
  194. package/dist/utils/stac.d.ts +0 -136
  195. package/dist/utils/stac.js +0 -176
  196. package/dist/utils/storage-url.d.ts +0 -90
  197. package/dist/utils/storage-url.js +0 -568
  198. package/dist/utils/wkb.d.ts +0 -43
  199. package/dist/utils/wkb.js +0 -359
@@ -4,13 +4,13 @@ import FileTextIcon from '@lucide/svelte/icons/file-text';
4
4
  import FolderIcon from '@lucide/svelte/icons/folder';
5
5
  import GlobeIcon from '@lucide/svelte/icons/globe';
6
6
  import InfoIcon from '@lucide/svelte/icons/info';
7
+ import { formatFileSize } from '@walkthru-earth/objex-utils';
7
8
  import { Separator } from '../ui/separator/index.js';
8
9
  import { getFileTypeInfo } from '../../file-icons/index.js';
9
10
  import { t } from '../../i18n/index.svelte.js';
10
11
  import { browser } from '../../stores/browser.svelte.js';
11
12
  import { files } from '../../stores/files.svelte.js';
12
13
  import { tabs } from '../../stores/tabs.svelte.js';
13
- import { formatFileSize } from '../../utils/format.js';
14
14
  import SafeLockToggle from './SafeLockToggle.svelte';
15
15
 
16
16
  let isBrowsingRemote = $derived(browser.activeConnection !== null);
@@ -32,29 +32,32 @@ let activeFileInfo = $derived(activeTab ? getFileTypeInfo(activeTab.extension) :
32
32
  {browser.activeConnection.name}
33
33
  </span>
34
34
  {#if displayPath}
35
- <span class="text-muted-foreground/50">/</span>
36
- <span class="max-w-[200px] truncate" title={displayPath}>{displayPath}</span>
35
+ <span class="hidden text-muted-foreground/50 sm:inline">/</span>
36
+ <span class="hidden max-w-[200px] truncate sm:inline" title={displayPath}>{displayPath}</span>
37
37
  {/if}
38
38
  <Separator orientation="vertical" class="mx-1.5 h-3.5" />
39
39
  {:else if displayPath}
40
- <FolderIcon class="size-3 shrink-0" />
41
- <span class="max-w-[300px] truncate" title={displayPath}>{displayPath}</span>
42
- <Separator orientation="vertical" class="mx-1.5 h-3.5" />
40
+ <FolderIcon class="hidden size-3 shrink-0 sm:block" />
41
+ <span class="hidden max-w-[300px] truncate sm:inline" title={displayPath}>{displayPath}</span>
42
+ <Separator orientation="vertical" class="mx-1.5 hidden h-3.5 sm:block" />
43
43
  {/if}
44
44
 
45
- <!-- Entry count -->
45
+ <!-- Entry count — hidden on mobile -->
46
46
  {#if displayCount > 0}
47
- <FileTextIcon class="size-3 shrink-0" />
48
- <span>{displayCount} {displayCount === 1 ? t('statusBar.item') : t('statusBar.items')}</span>
49
- <Separator orientation="vertical" class="mx-1.5 h-3.5" />
47
+ <FileTextIcon class="hidden size-3 shrink-0 sm:block" />
48
+ <span class="hidden sm:inline"
49
+ >{displayCount}
50
+ {displayCount === 1 ? t('statusBar.item') : t('statusBar.items')}</span
51
+ >
52
+ <Separator orientation="vertical" class="mx-1.5 hidden h-3.5 sm:block" />
50
53
  {/if}
51
54
 
52
- <!-- Active file info -->
55
+ <!-- Active file info: type label hidden on mobile, size kept -->
53
56
  {#if activeTab && activeFileInfo}
54
- <InfoIcon class="size-3 shrink-0" />
55
- <span>{activeFileInfo.label}</span>
57
+ <InfoIcon class="hidden size-3 shrink-0 sm:block" />
58
+ <span class="hidden sm:inline">{activeFileInfo.label}</span>
56
59
  {#if activeTab.size}
57
- <span class="text-muted-foreground/50">·</span>
60
+ <span class="hidden text-muted-foreground/50 sm:inline">·</span>
58
61
  <span>{formatFileSize(activeTab.size)}</span>
59
62
  {/if}
60
63
  <Separator orientation="vertical" class="mx-1.5 h-3.5" />
@@ -2,14 +2,14 @@
2
2
  import DatabaseIcon from '@lucide/svelte/icons/database';
3
3
  import FileTextIcon from '@lucide/svelte/icons/file-text';
4
4
  import XIcon from '@lucide/svelte/icons/x';
5
+ import { copyToClipboard } from '@walkthru-earth/objex-utils';
5
6
  import type { Snippet } from 'svelte';
6
7
  import { Button } from '../ui/button/index.js';
7
8
  import * as ContextMenu from '../ui/context-menu/index.js';
8
9
  import { ScrollArea } from '../ui/scroll-area/index.js';
9
10
  import { t } from '../../i18n/index.svelte.js';
10
11
  import { tabs } from '../../stores/tabs.svelte.js';
11
- import { copyToClipboard } from '../../utils/clipboard.js';
12
- import { buildHttpsUrl, buildStorageUrl } from '../../utils/url.js';
12
+ import { buildHttpsUrl, buildStorageUrl } from '../../utils/signed-url.js';
13
13
 
14
14
  let { leading }: { leading?: Snippet } = $props();
15
15
 
@@ -60,8 +60,8 @@ async function handleCopy(type: 'https' | 's3', tab: (typeof tabs.items)[0]) {
60
60
  <Button
61
61
  variant="ghost"
62
62
  size="icon-sm"
63
- class="ms-1 size-5 opacity-0 transition-opacity group-hover:opacity-100
64
- {isActive ? 'opacity-60' : ''}"
63
+ class="ms-1 size-5 opacity-100 transition-opacity sm:opacity-0 sm:group-hover:opacity-100
64
+ {isActive ? 'sm:opacity-60' : ''}"
65
65
  onclick={(e: MouseEvent) => handleClose(e, tab.id)}
66
66
  aria-label={t('tabBar.closeTab', { name: tab.name })}
67
67
  >
@@ -1,4 +1,4 @@
1
1
  import { ContextMenu as ContextMenuPrimitive } from 'bits-ui';
2
- declare const ContextMenuRadioGroup: import("svelte").Component<ContextMenuPrimitive.RadioGroupProps, {}, "value" | "ref">;
2
+ declare const ContextMenuRadioGroup: import("svelte").Component<ContextMenuPrimitive.RadioGroupProps, {}, "ref" | "value">;
3
3
  type ContextMenuRadioGroup = ReturnType<typeof ContextMenuRadioGroup>;
4
4
  export default ContextMenuRadioGroup;
@@ -1,4 +1,4 @@
1
1
  import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
2
- declare const DropdownMenuCheckboxGroup: import("svelte").Component<DropdownMenuPrimitive.CheckboxGroupProps, {}, "value" | "ref">;
2
+ declare const DropdownMenuCheckboxGroup: import("svelte").Component<DropdownMenuPrimitive.CheckboxGroupProps, {}, "ref" | "value">;
3
3
  type DropdownMenuCheckboxGroup = ReturnType<typeof DropdownMenuCheckboxGroup>;
4
4
  export default DropdownMenuCheckboxGroup;
@@ -1,4 +1,4 @@
1
1
  import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
2
- declare const DropdownMenuRadioGroup: import("svelte").Component<DropdownMenuPrimitive.RadioGroupProps, {}, "value" | "ref">;
2
+ declare const DropdownMenuRadioGroup: import("svelte").Component<DropdownMenuPrimitive.RadioGroupProps, {}, "ref" | "value">;
3
3
  type DropdownMenuRadioGroup = ReturnType<typeof DropdownMenuRadioGroup>;
4
4
  export default DropdownMenuRadioGroup;
@@ -8,6 +8,6 @@ type Props = WithElementRef<Omit<HTMLInputAttributes, 'type'> & ({
8
8
  type?: InputType;
9
9
  files?: undefined;
10
10
  })>;
11
- declare const Input: import("svelte").Component<Props, {}, "value" | "ref" | "files">;
11
+ declare const Input: import("svelte").Component<Props, {}, "ref" | "value" | "files">;
12
12
  type Input = ReturnType<typeof Input>;
13
13
  export default Input;
@@ -1,4 +1,4 @@
1
1
  import { Pane } from 'paneforge';
2
2
  import Handle from './resizable-handle.svelte';
3
3
  import PaneGroup from './resizable-pane-group.svelte';
4
- export { PaneGroup, Pane, Handle, PaneGroup as ResizablePaneGroup, Pane as ResizablePane, Handle as ResizableHandle };
4
+ export { Handle, Handle as ResizableHandle, Pane as ResizablePane, PaneGroup, PaneGroup as ResizablePaneGroup };
@@ -1,6 +1,6 @@
1
1
  import { Pane } from 'paneforge';
2
2
  import Handle from './resizable-handle.svelte';
3
3
  import PaneGroup from './resizable-pane-group.svelte';
4
- export { PaneGroup, Pane, Handle,
4
+ export { Handle, Handle as ResizableHandle, Pane as ResizablePane, PaneGroup,
5
5
  //
6
- PaneGroup as ResizablePaneGroup, Pane as ResizablePane, Handle as ResizableHandle };
6
+ PaneGroup as ResizablePaneGroup };
@@ -0,0 +1,3 @@
1
+ import RangeSlider from './range-slider.svelte';
2
+ import Root from './slider.svelte';
3
+ export { RangeSlider, Root, Root as Slider };
@@ -0,0 +1,5 @@
1
+ import RangeSlider from './range-slider.svelte';
2
+ import Root from './slider.svelte';
3
+ export { RangeSlider, Root,
4
+ //
5
+ Root as Slider };
@@ -0,0 +1,94 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../../utils.js';
3
+ import Slider from './slider.svelte';
4
+
5
+ /**
6
+ * Dual-thumb numeric range slider with optional histogram bars rendered
7
+ * behind the track and a min/max label row beneath. Composes the shadcn
8
+ * `Slider` primitive (bits-ui) so pointer, keyboard, RTL, and a11y
9
+ * behavior come from the primitive instead of being reimplemented.
10
+ *
11
+ * Used by:
12
+ * - StacDatetimeBar / StacFilterPanel (datetime + numeric facets, with histogram)
13
+ * - CogControls (rescale min/max, no histogram, paired number inputs)
14
+ */
15
+ let {
16
+ value = $bindable<[number, number]>([0, 1]),
17
+ min,
18
+ max,
19
+ step = 1,
20
+ histogram,
21
+ formatLabel,
22
+ loLabel,
23
+ hiLabel,
24
+ class: className,
25
+ disabled = false,
26
+ onValueChange,
27
+ onValueCommit
28
+ }: {
29
+ value?: [number, number];
30
+ min: number;
31
+ max: number;
32
+ step?: number;
33
+ /** Optional bin counts to draw behind the track. */
34
+ histogram?: readonly number[] | null;
35
+ /** Formatter for the default min/max label row. Omit to hide labels. */
36
+ formatLabel?: (n: number) => string;
37
+ /** Override the lower label (takes precedence over `formatLabel(value[0])`). */
38
+ loLabel?: string;
39
+ /** Override the upper label (takes precedence over `formatLabel(value[1])`). */
40
+ hiLabel?: string;
41
+ class?: string;
42
+ disabled?: boolean;
43
+ onValueChange?: (next: [number, number]) => void;
44
+ onValueCommit?: (next: [number, number]) => void;
45
+ } = $props();
46
+
47
+ const histMax = $derived(histogram?.length ? Math.max(1, ...histogram) : 1);
48
+ const showLabels = $derived(Boolean(formatLabel) || loLabel != null || hiLabel != null);
49
+
50
+ function emitChange(next: number[]): void {
51
+ if (next.length >= 2) onValueChange?.([next[0], next[1]]);
52
+ }
53
+
54
+ function emitCommit(next: number[]): void {
55
+ if (next.length >= 2) onValueCommit?.([next[0], next[1]]);
56
+ }
57
+ </script>
58
+
59
+ <div class={cn('flex flex-col gap-1.5', className)}>
60
+ <div class="relative px-2">
61
+ {#if histogram && histogram.length > 0}
62
+ <div
63
+ class="pointer-events-none absolute inset-x-2 top-0 flex h-6 items-end gap-px"
64
+ aria-hidden="true"
65
+ >
66
+ {#each histogram as count, i (i)}
67
+ <div
68
+ class="bg-muted-foreground/30 flex-1 rounded-sm"
69
+ style="height: {Math.max(2, (count / histMax) * 100)}%"
70
+ ></div>
71
+ {/each}
72
+ </div>
73
+ {/if}
74
+ <Slider
75
+ type="multiple"
76
+ bind:value={value as never}
77
+ {min}
78
+ {max}
79
+ {step}
80
+ {disabled}
81
+ onValueChange={emitChange}
82
+ onValueCommit={emitCommit}
83
+ class={cn(histogram && histogram.length > 0 && 'mt-7')}
84
+ />
85
+ </div>
86
+ {#if showLabels}
87
+ <div
88
+ class="text-muted-foreground flex items-center justify-between px-2 text-[10px] tabular-nums"
89
+ >
90
+ <span>{loLabel ?? (formatLabel ? formatLabel(value[0]) : '')}</span>
91
+ <span>{hiLabel ?? (formatLabel ? formatLabel(value[1]) : '')}</span>
92
+ </div>
93
+ {/if}
94
+ </div>
@@ -0,0 +1,21 @@
1
+ type $$ComponentProps = {
2
+ value?: [number, number];
3
+ min: number;
4
+ max: number;
5
+ step?: number;
6
+ /** Optional bin counts to draw behind the track. */
7
+ histogram?: readonly number[] | null;
8
+ /** Formatter for the default min/max label row. Omit to hide labels. */
9
+ formatLabel?: (n: number) => string;
10
+ /** Override the lower label (takes precedence over `formatLabel(value[0])`). */
11
+ loLabel?: string;
12
+ /** Override the upper label (takes precedence over `formatLabel(value[1])`). */
13
+ hiLabel?: string;
14
+ class?: string;
15
+ disabled?: boolean;
16
+ onValueChange?: (next: [number, number]) => void;
17
+ onValueCommit?: (next: [number, number]) => void;
18
+ };
19
+ declare const RangeSlider: import("svelte").Component<$$ComponentProps, {}, "value">;
20
+ type RangeSlider = ReturnType<typeof RangeSlider>;
21
+ export default RangeSlider;
@@ -0,0 +1,83 @@
1
+ <script lang="ts" module>
2
+ import { Slider as SliderPrimitive, type WithoutChildrenOrChild } from 'bits-ui';
3
+
4
+ export type SliderProps = WithoutChildrenOrChild<SliderPrimitive.RootProps> & {
5
+ class?: string;
6
+ };
7
+ </script>
8
+
9
+ <script lang="ts">
10
+ import { cn } from '../../../utils.js';
11
+
12
+ let {
13
+ ref = $bindable(null),
14
+ value = $bindable(),
15
+ class: className,
16
+ type,
17
+ ...restProps
18
+ }: SliderProps = $props();
19
+ </script>
20
+
21
+ {#if type === 'single'}
22
+ <SliderPrimitive.Root
23
+ bind:ref
24
+ bind:value={value as never}
25
+ type="single"
26
+ data-slot="slider"
27
+ class={cn(
28
+ 'relative flex w-full touch-none select-none items-center data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col data-[disabled]:opacity-50',
29
+ className
30
+ )}
31
+ {...(restProps as Record<string, unknown>)}
32
+ >
33
+ {#snippet children({ thumbs })}
34
+ <span
35
+ data-slot="slider-track"
36
+ class="bg-muted relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5"
37
+ >
38
+ <SliderPrimitive.Range
39
+ data-slot="slider-range"
40
+ class="bg-primary absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
41
+ />
42
+ </span>
43
+ {#each thumbs as index (index)}
44
+ <SliderPrimitive.Thumb
45
+ {index}
46
+ data-slot="slider-thumb"
47
+ class="border-primary bg-background ring-ring/50 block size-4 shrink-0 cursor-pointer rounded-full border-2 shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50"
48
+ />
49
+ {/each}
50
+ {/snippet}
51
+ </SliderPrimitive.Root>
52
+ {:else}
53
+ <SliderPrimitive.Root
54
+ bind:ref
55
+ bind:value={value as never}
56
+ type="multiple"
57
+ data-slot="slider"
58
+ class={cn(
59
+ 'relative flex w-full touch-none select-none items-center data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col data-[disabled]:opacity-50',
60
+ className
61
+ )}
62
+ {...(restProps as Record<string, unknown>)}
63
+ >
64
+ {#snippet children({ thumbs })}
65
+ <span
66
+ data-slot="slider-track"
67
+ class="bg-muted relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5"
68
+ >
69
+ <SliderPrimitive.Range
70
+ data-slot="slider-range"
71
+ class="bg-primary absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
72
+ />
73
+ </span>
74
+ {#each thumbs as index (index)}
75
+ <SliderPrimitive.Thumb
76
+ {index}
77
+ data-slot="slider-thumb"
78
+ class="border-primary bg-background ring-ring/50 block size-4 shrink-0 cursor-pointer rounded-full border-2 shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50"
79
+ />
80
+ {/each}
81
+ {/snippet}
82
+ </SliderPrimitive.Root>
83
+ {/if}
@@ -0,0 +1,7 @@
1
+ import { Slider as SliderPrimitive, type WithoutChildrenOrChild } from 'bits-ui';
2
+ export type SliderProps = WithoutChildrenOrChild<SliderPrimitive.RootProps> & {
3
+ class?: string;
4
+ };
5
+ declare const Slider: import("svelte").Component<SliderProps, {}, "ref" | "value">;
6
+ type Slider = ReturnType<typeof Slider>;
7
+ export default Slider;