@connectorvol/tree 8.0.1 → 9.0.1

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 (43) hide show
  1. package/dist/(components)/BoardSettingsTrigger.svelte +10 -0
  2. package/dist/(components)/BoardSettingsTrigger.svelte.d.ts +18 -0
  3. package/dist/(components)/DrillBreadcrumbs.svelte +6 -8
  4. package/dist/(components)/DrillBreadcrumbs.svelte.d.ts +0 -3
  5. package/dist/(components)/DrillForkSanLabel.svelte +2 -5
  6. package/dist/(components)/DrillForkSanLabel.svelte.d.ts +0 -3
  7. package/dist/(components)/DrillVariationList.svelte +29 -15
  8. package/dist/(components)/DrillVariationList.svelte.d.ts +0 -3
  9. package/dist/(components)/Move.svelte +348 -349
  10. package/dist/(components)/Move.svelte.d.ts +0 -3
  11. package/dist/(components)/MoveComment.svelte +31 -24
  12. package/dist/(components)/MoveComment.svelte.d.ts +2 -0
  13. package/dist/(components)/MoveSanWithMenu.svelte +4 -7
  14. package/dist/(components)/MoveSanWithMenu.svelte.d.ts +0 -3
  15. package/dist/(components)/MoveWithIcon.svelte +60 -65
  16. package/dist/(components)/MoveWithIcon.svelte.d.ts +1 -4
  17. package/dist/(components)/PieceIcon.svelte +27 -44
  18. package/dist/(components)/PieceIcon.svelte.d.ts +3 -6
  19. package/dist/(components)/TreeViewer.svelte +957 -907
  20. package/dist/(components)/TreeViewer.svelte.d.ts +10 -3
  21. package/dist/(components)/VariantDropdownNavigator.svelte +22 -6
  22. package/dist/(components)/VariantDropdownNavigator.svelte.d.ts +8 -3
  23. package/dist/(components)/VariationGroup.svelte +85 -89
  24. package/dist/(constants)/treeViewerThemes.d.ts +12 -0
  25. package/dist/(constants)/treeViewerThemes.js +19 -0
  26. package/dist/(models)/treeViewerTheme.d.ts +17 -0
  27. package/dist/(models)/treeViewerTheme.js +1 -0
  28. package/dist/(utils)/treeViewerPanelNavigation.svelte.d.ts +2 -2
  29. package/dist/(utils)/treeViewerPanelNavigation.svelte.js +12 -5
  30. package/dist/components/ui/context-menu/context-menu-content.svelte +24 -20
  31. package/dist/components/ui/context-menu/context-menu-sub-content.svelte +14 -14
  32. package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte +26 -22
  33. package/dist/components/ui/toggle/index.d.ts +1 -1
  34. package/dist/components/ui/toggle/index.js +1 -1
  35. package/dist/components/ui/toggle/toggle-variants.d.ts +35 -0
  36. package/dist/components/ui/toggle/toggle-variants.js +19 -0
  37. package/dist/components/ui/toggle/toggle.svelte +1 -27
  38. package/dist/components/ui/toggle/toggle.svelte.d.ts +1 -35
  39. package/dist/index.d.ts +3 -1
  40. package/dist/index.js +2 -1
  41. package/dist/utils/overlayPortalTarget.d.ts +6 -0
  42. package/dist/utils/overlayPortalTarget.js +15 -0
  43. package/package.json +15 -14
@@ -1,7 +1,8 @@
1
1
  import type { ClassValue } from "svelte/elements";
2
2
  import { ChessTree } from "../(classes)/chessTree.svelte.js";
3
3
  import type { ChessTreeNode } from "../(models)/chessTreeNode.js";
4
- import type { Move as TSharedMove, PieceSet } from "@connectorvol/shared";
4
+ import type { Move as TSharedMove } from "@connectorvol/shared";
5
+ import type { TTreeViewerTheme } from "../(models)/treeViewerTheme.js";
5
6
  type TPreviewOnHoverChessNodeSettings = {
6
7
  /** Возвращает функцию для установки FEN превью при наведении (null скрывает); второй аргумент — подсветка последнего хода. */
7
8
  setPreviewFen?: (fen: string | null, lastMove?: TSharedMove | null) => void;
@@ -23,8 +24,6 @@ type TTreeViewerProps = {
23
24
  setChessFen: (fen: string) => void;
24
25
  /** Возвращает функцию обновления доски. */
25
26
  setChessboardFen: (animationTime?: number) => void;
26
- /** Возвращает набор фигур для иконок SAN. */
27
- pieceSet: PieceSet;
28
27
  /** Возвращает true, если клик по ходу переключает текущий узел и доску. По умолчанию true. */
29
28
  selectable?: boolean;
30
29
  /** Возвращает настройки превью-доски при наведении на ноду. */
@@ -39,6 +38,14 @@ type TTreeViewerProps = {
39
38
  showPuzzleBranchNags?: boolean;
40
39
  /** Возвращает функцию для установки признака несохранённости дерева. */
41
40
  onChangeDirty?: (setIsDirty: (value: boolean) => void) => void;
41
+ /**
42
+ * Возвращает настройки оформления: фон, границы и цвет текста.
43
+ * Обязателен: без явного `theme` стили падают на CSS-дефолт и сетка
44
+ * выглядит бледной. Если нужно подставить готовую тему — импортируйте
45
+ * `TREE_VIEWER_LIGHT_THEME` или `TREE_VIEWER_DARK_THEME` из
46
+ * `@connectorvol/tree`.
47
+ */
48
+ theme: TTreeViewerTheme;
42
49
  };
43
50
  declare const TreeViewer: import("svelte").Component<TTreeViewerProps, {}, "">;
44
51
  type TreeViewer = ReturnType<typeof TreeViewer>;
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { ChessTreeNode } from "../(models)/chessTreeNode.js";
3
- import type { PieceSet } from "@connectorvol/shared";
3
+ import type { TTreeViewerTheme } from "../(models)/treeViewerTheme.js";
4
4
  import NagBadges from "./NagBadges.svelte";
5
5
  import MoveWithIcon from "./MoveWithIcon.svelte";
6
6
  type Props = {
@@ -10,11 +10,21 @@
10
10
  * Представляет CSS-селектор элемента, относительно которого нужно позиционировать dropdown.
11
11
  */
12
12
  anchorSelector?: string;
13
- /** Возвращает набор фигур для иконок SAN. */
14
- pieceSet: PieceSet;
13
+ /**
14
+ * Возвращает настройки оформления, заданные в `TreeViewer` через prop `theme`.
15
+ * При наличии применяются к контейнеру дропдауна; без темы дропдаун
16
+ * опирается на утилиты `bg-popover`/`text-popover-foreground`,
17
+ * которые реагируют на dark-режим приложения.
18
+ */
19
+ theme?: TTreeViewerTheme;
15
20
  };
16
21
 
17
- const { variants, onActivateVariant, anchorSelector = "", pieceSet }: Props = $props();
22
+ const {
23
+ variants,
24
+ onActivateVariant,
25
+ anchorSelector = "",
26
+ theme,
27
+ }: Props = $props();
18
28
 
19
29
  let requestedOpen = $state(false);
20
30
  let activeIndex = $state(0);
@@ -141,9 +151,15 @@
141
151
  {#if isOpen}
142
152
  <div
143
153
  data-variant-dropdown="1"
144
- class="z-50 min-w-[14rem] rounded-md border bg-white p-1 shadow-none outline-none"
154
+ class="z-50 min-w-[14rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-none outline-none"
145
155
  role="menu"
146
156
  aria-label="Варианты следующего хода"
157
+ style:--tree-viewer-bg={theme?.background}
158
+ style:--tree-viewer-border={theme?.border}
159
+ style:--tree-viewer-text={theme?.text}
160
+ style:background-color={theme ? "var(--tree-viewer-bg)" : undefined}
161
+ style:border-color={theme ? "var(--tree-viewer-border)" : undefined}
162
+ style:color={theme ? "var(--tree-viewer-text)" : undefined}
147
163
  style={position
148
164
  ? `position: fixed; left: ${position.left}px; top: ${position.top}px;`
149
165
  : "position: fixed;"}
@@ -168,7 +184,7 @@
168
184
  {#if getMovePrefix(variant)}
169
185
  <span>{getMovePrefix(variant)}</span>
170
186
  {/if}
171
- <MoveWithIcon san={variant.data.san} ply={variant.data.ply} {pieceSet} />
187
+ <MoveWithIcon san={variant.data.san} ply={variant.data.ply} />
172
188
  <NagBadges nags={variant.data.nags} class="!ml-0" />
173
189
  </span>
174
190
  </button>
@@ -1,5 +1,5 @@
1
1
  import type { ChessTreeNode } from "../(models)/chessTreeNode.js";
2
- import type { PieceSet } from "@connectorvol/shared";
2
+ import type { TTreeViewerTheme } from "../(models)/treeViewerTheme.js";
3
3
  type Props = {
4
4
  variants: ChessTreeNode[];
5
5
  onActivateVariant: (node: ChessTreeNode) => void;
@@ -7,8 +7,13 @@ type Props = {
7
7
  * Представляет CSS-селектор элемента, относительно которого нужно позиционировать dropdown.
8
8
  */
9
9
  anchorSelector?: string;
10
- /** Возвращает набор фигур для иконок SAN. */
11
- pieceSet: PieceSet;
10
+ /**
11
+ * Возвращает настройки оформления, заданные в `TreeViewer` через prop `theme`.
12
+ * При наличии применяются к контейнеру дропдауна; без темы дропдаун
13
+ * опирается на утилиты `bg-popover`/`text-popover-foreground`,
14
+ * которые реагируют на dark-режим приложения.
15
+ */
16
+ theme?: TTreeViewerTheme;
12
17
  };
13
18
  declare const VariantDropdownNavigator: import("svelte").Component<Props, {
14
19
  forceClose: () => void;
@@ -1,100 +1,96 @@
1
1
  <script lang="ts">
2
- import type { Snippet } from "svelte";
3
- import type { ChessTreeNode } from "../(models)/chessTreeNode.js";
2
+ import type { Snippet } from "svelte";
3
+ import type { ChessTreeNode } from "../(models)/chessTreeNode.js";
4
4
 
5
- type TVariationGroupProps = {
6
- /** Возвращает родительский узел-развилку. */
7
- parentNode: ChessTreeNode;
8
- /** Возвращает true, если блок в верхней строке сетки дерева. */
9
- isHighestLevel: boolean;
10
- /** Возвращает true, если вертикальная направляющая должна быть акцентной. */
11
- isActiveForkForSelection: boolean;
12
- /** Возвращает true, если доступен drill-down «варианты отдельно». */
13
- showVariationDrillExpand: boolean;
14
- /** Представляет обработчик клика по зоне открытия drill-down. */
15
- onVariationLinesHit: (e: MouseEvent) => void;
16
- /** Возвращает фрагмент разметки одного дочернего варианта. */
17
- variationMoveRow: Snippet<[ChessTreeNode]>;
18
- /** Возвращает true, если ветка текущего выбора проходит через узел (для «птички»). */
19
- isBranchOnCurrentPath: (node: ChessTreeNode) => boolean;
20
- };
5
+ type TVariationGroupProps = {
6
+ /** Возвращает родительский узел-развилку. */
7
+ parentNode: ChessTreeNode;
8
+ /** Возвращает true, если блок в верхней строке сетки дерева. */
9
+ isHighestLevel: boolean;
10
+ /** Возвращает true, если вертикальная направляющая должна быть акцентной. */
11
+ isActiveForkForSelection: boolean;
12
+ /** Возвращает true, если доступен drill-down «варианты отдельно». */
13
+ showVariationDrillExpand: boolean;
14
+ /** Представляет обработчик клика по зоне открытия drill-down. */
15
+ onVariationLinesHit: (e: MouseEvent) => void;
16
+ /** Возвращает фрагмент разметки одного дочернего варианта. */
17
+ variationMoveRow: Snippet<[ChessTreeNode]>;
18
+ /** Возвращает true, если ветка текущего выбора проходит через узел (для «птички»). */
19
+ isBranchOnCurrentPath: (node: ChessTreeNode) => boolean;
20
+ };
21
21
 
22
- const {
23
- parentNode,
24
- isHighestLevel,
25
- isActiveForkForSelection,
26
- showVariationDrillExpand,
27
- onVariationLinesHit,
28
- variationMoveRow,
29
- isBranchOnCurrentPath,
30
- }: TVariationGroupProps = $props();
22
+ const {
23
+ parentNode,
24
+ isHighestLevel,
25
+ isActiveForkForSelection,
26
+ showVariationDrillExpand,
27
+ onVariationLinesHit,
28
+ variationMoveRow,
29
+ isBranchOnCurrentPath,
30
+ }: TVariationGroupProps = $props();
31
31
  </script>
32
32
 
33
33
  <div
34
- class={{
35
- "col-span-3 col-start-1 w-full min-w-0": isHighestLevel,
36
- "block w-full min-w-0 basis-full shrink-0": !isHighestLevel,
37
- }}
34
+ class={{
35
+ "col-span-3 col-start-1 w-full min-w-0": isHighestLevel,
36
+ "block w-full min-w-0 basis-full shrink-0": !isHighestLevel,
37
+ }}
38
38
  >
39
- {#if parentNode.children.length > 1}
39
+ {#if parentNode.children.length > 1}
40
+ <div
41
+ class={{
42
+ "relative min-w-0 w-full max-w-full": true,
43
+ " rounded-md transition-[border-color,box-shadow] duration-150 [&:has(>[data-line-hit]:hover)>.flex>div[data-line-stroke]]:opacity-100 [&:has(>[data-line-hit]:hover)>.flex>ul>li>span[data-line-stroke]]:opacity-100 [&:has(>[data-line-hit]:focus-visible)>.flex>div[data-line-stroke]]:opacity-100 [&:has(>[data-line-hit]:focus-visible)>.flex>ul>li>span[data-line-stroke]]:opacity-100 ":
44
+ showVariationDrillExpand,
45
+ "pr-2": !showVariationDrillExpand,
46
+ }}
47
+ style:background-color="var(--tree-viewer-bg)"
48
+ >
49
+ <div class="flex min-w-0 w-full max-w-full gap-0 align-top">
40
50
  <div
41
- class={{
42
- "relative min-w-0 w-full max-w-full bg-gray-50/95 ": true,
43
- " rounded-md transition-[border-color,box-shadow] duration-150 [&:has(>[data-line-hit]:hover)>.flex>div[data-line-stroke]]:border-gray-600 [&:has(>[data-line-hit]:hover)>.flex>ul>li>span[data-line-stroke]]:border-gray-600 [&:has(>[data-line-hit]:focus-visible)>.flex>div[data-line-stroke]]:border-gray-600 [&:has(>[data-line-hit]:focus-visible)>.flex>ul>li>span[data-line-stroke]]:border-gray-600 ":
44
- showVariationDrillExpand,
45
- "pr-2": !showVariationDrillExpand,
46
- }}
51
+ class={{
52
+ "w-2 shrink-0 self-stretch border-r-2 transition-opacity duration-150": true,
53
+ "pointer-events-none": showVariationDrillExpand,
54
+ "opacity-50": !isActiveForkForSelection,
55
+ }}
56
+ style:border-color="var(--tree-viewer-border)"
57
+ data-line-stroke
58
+ aria-hidden="true"
59
+ ></div>
60
+ <ul
61
+ class="m-0 flex min-w-0 flex-1 list-none flex-col gap-1.5 py-2 pl-0"
47
62
  >
48
- <div class="flex min-w-0 w-full max-w-full gap-0 align-top">
49
- <div
50
- class={{
51
- "w-2 shrink-0 self-stretch border-r-2 transition-[border-color] duration-150": true,
52
- "border-gray-600": isActiveForkForSelection,
53
- "border-gray-300": !isActiveForkForSelection,
54
- "pointer-events-none": showVariationDrillExpand,
55
- }}
56
- data-line-stroke
57
- aria-hidden="true"
58
- ></div>
59
- <ul
60
- class="m-0 flex min-w-0 flex-1 list-none flex-col gap-1.5 py-2 pl-0"
61
- >
62
- {#each parentNode.children as child, index (child.id)}
63
- {#if !isHighestLevel || index >= 1}
64
- {@const branchOnPath = isBranchOnCurrentPath(child)}
65
- <li class="relative min-w-0 pl-3">
66
- <span
67
- class={{
68
- "absolute left-0 top-[0.65em] w-3 border-t-2 transition-[border-color] duration-150": true,
69
- "border-gray-600":
70
- isActiveForkForSelection &&
71
- branchOnPath,
72
- "border-gray-300":
73
- !isActiveForkForSelection ||
74
- !branchOnPath,
75
- "pointer-events-none":
76
- showVariationDrillExpand,
77
- }}
78
- data-line-stroke
79
- aria-hidden="true"
80
- ></span>
81
- <div class="tracking-tight">
82
- {@render variationMoveRow(child)}
83
- </div>
84
- </li>
85
- {/if}
86
- {/each}
87
- </ul>
88
- </div>
89
- {#if showVariationDrillExpand}
90
- <button
91
- type="button"
92
- class="absolute left-0 top-0 z-20 h-full w-5 max-w-full cursor-pointer border-0 bg-transparent p-0 focus:outline-none focus-visible:ring-0"
93
- data-line-hit
94
- aria-label="Открыть варианты отдельно"
95
- onclick={onVariationLinesHit}
96
- ></button>
63
+ {#each parentNode.children as child, index (child.id)}
64
+ {#if !isHighestLevel || index >= 1}
65
+ {@const branchOnPath = isBranchOnCurrentPath(child)}
66
+ <li class="relative min-w-0 pl-3">
67
+ <span
68
+ class={{
69
+ "absolute left-0 top-[0.65em] w-3 border-t-2 transition-opacity duration-150": true,
70
+ "pointer-events-none": showVariationDrillExpand,
71
+ "opacity-50": !(isActiveForkForSelection && branchOnPath),
72
+ }}
73
+ style:border-color="var(--tree-viewer-border)"
74
+ data-line-stroke
75
+ aria-hidden="true"
76
+ ></span>
77
+ <div class="tracking-tight">
78
+ {@render variationMoveRow(child)}
79
+ </div>
80
+ </li>
97
81
  {/if}
98
- </div>
99
- {/if}
82
+ {/each}
83
+ </ul>
84
+ </div>
85
+ {#if showVariationDrillExpand}
86
+ <button
87
+ type="button"
88
+ class="absolute left-0 top-0 z-20 h-full w-5 max-w-full cursor-pointer border-0 bg-transparent p-0 focus:outline-none focus-visible:ring-0"
89
+ data-line-hit
90
+ aria-label="Открыть варианты отдельно"
91
+ onclick={onVariationLinesHit}
92
+ ></button>
93
+ {/if}
94
+ </div>
95
+ {/if}
100
96
  </div>
@@ -0,0 +1,12 @@
1
+ import type { TTreeViewerTheme } from "../(models)/treeViewerTheme.js";
2
+ /**
3
+ * Тёмная тема `TreeViewer`, выровненная по палитре с `CHESSBOARD_THEMES.dark`:
4
+ * фон = `b` доски (zinc-700), границы = `w` доски (zinc-500), текст белый.
5
+ * Не зависит от light/dark режима приложения — стиль одинаков в обоих.
6
+ */
7
+ export declare const TREE_VIEWER_DARK_THEME: TTreeViewerTheme;
8
+ /**
9
+ * Светлая тема `TreeViewer`: белый фон, gray-300 границы, zinc-900 текст.
10
+ * Не зависит от light/dark режима приложения — стиль одинаков в обоих.
11
+ */
12
+ export declare const TREE_VIEWER_LIGHT_THEME: TTreeViewerTheme;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Тёмная тема `TreeViewer`, выровненная по палитре с `CHESSBOARD_THEMES.dark`:
3
+ * фон = `b` доски (zinc-700), границы = `w` доски (zinc-500), текст белый.
4
+ * Не зависит от light/dark режима приложения — стиль одинаков в обоих.
5
+ */
6
+ export const TREE_VIEWER_DARK_THEME = {
7
+ background: "rgb(20, 20, 20)",
8
+ border: "rgb(50, 50, 50)",
9
+ text: "rgb(200, 200, 200)",
10
+ };
11
+ /**
12
+ * Светлая тема `TreeViewer`: белый фон, gray-300 границы, zinc-900 текст.
13
+ * Не зависит от light/dark режима приложения — стиль одинаков в обоих.
14
+ */
15
+ export const TREE_VIEWER_LIGHT_THEME = {
16
+ background: "oklch(1 0 0)",
17
+ border: "oklch(0.872 0.01 286)",
18
+ text: "oklch(0.21 0.006 285.885)",
19
+ };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Представляет настройки оформления дерева ходов.
3
+ * При передаче компоненту `TreeViewer` переопределяет светлые/тёмные
4
+ * оттенки серого на единую палитру. Стиль при этом не зависит от
5
+ * light/dark режима приложения.
6
+ */
7
+ export type TTreeViewerTheme = {
8
+ /** Возвращает цвет фона (фон сетки, фон ячеек, фон панели правки). */
9
+ background: string;
10
+ /** Возвращает цвет границ и разделителей. */
11
+ border: string;
12
+ /**
13
+ * Возвращает цвет текста и placeholder. Задаётся отдельно от `border`,
14
+ * чтобы яркость шрифта не была привязана к толщине разделителей.
15
+ */
16
+ text: string;
17
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -15,13 +15,13 @@ export type TTreeViewerPanelNavigation = ReturnType<typeof createTreeViewerPanel
15
15
  declare function createTreeViewerPanelNavigation(chessTree: ChessTree): {
16
16
  bindCallbacks: (setChessFen: (fen: string) => void, setChessboardFen: (animationTime?: number) => void) => void;
17
17
  setVariantNavigator: (nav: TVariantNavigatorHandle | null) => void;
18
- highlightedButtons: {
18
+ readonly highlightedButtons: {
19
19
  previous: boolean;
20
20
  next: boolean;
21
21
  start: boolean;
22
22
  end: boolean;
23
23
  };
24
- isPlaying: boolean;
24
+ readonly isPlaying: boolean;
25
25
  onWindowKeyDown: (e: KeyboardEvent) => void;
26
26
  dispose: () => void;
27
27
  selectPreviousNode: () => void;
@@ -160,7 +160,8 @@ function createTreeViewerPanelNavigation(chessTree) {
160
160
  }
161
161
  if (e.key === "ArrowUp") {
162
162
  variantNavigator?.forceClose();
163
- if (chessTree.isVariationDrillDownActive() && isCurrentNodeInDrillHeader()) {
163
+ if (chessTree.isVariationDrillDownActive() &&
164
+ isCurrentNodeInDrillHeader()) {
164
165
  requestDrillExitPrompt();
165
166
  e.preventDefault();
166
167
  return;
@@ -172,7 +173,8 @@ function createTreeViewerPanelNavigation(chessTree) {
172
173
  }
173
174
  else if (e.key === "ArrowDown") {
174
175
  variantNavigator?.forceClose();
175
- if (chessTree.isVariationDrillDownActive() && isCurrentNodeInDrillHeader()) {
176
+ if (chessTree.isVariationDrillDownActive() &&
177
+ isCurrentNodeInDrillHeader()) {
176
178
  requestDrillExitPrompt();
177
179
  e.preventDefault();
178
180
  return;
@@ -182,7 +184,8 @@ function createTreeViewerPanelNavigation(chessTree) {
182
184
  }
183
185
  else if (e.key === "ArrowLeft") {
184
186
  variantNavigator?.forceClose();
185
- if (chessTree.isVariationDrillDownActive() && isCurrentNodeInDrillHeader()) {
187
+ if (chessTree.isVariationDrillDownActive() &&
188
+ isCurrentNodeInDrillHeader()) {
186
189
  requestDrillExitPrompt();
187
190
  e.preventDefault();
188
191
  return;
@@ -228,8 +231,12 @@ function createTreeViewerPanelNavigation(chessTree) {
228
231
  return {
229
232
  bindCallbacks,
230
233
  setVariantNavigator,
231
- highlightedButtons,
232
- isPlaying,
234
+ get highlightedButtons() {
235
+ return highlightedButtons;
236
+ },
237
+ get isPlaying() {
238
+ return isPlaying;
239
+ },
233
240
  onWindowKeyDown,
234
241
  dispose,
235
242
  selectPreviousNode,
@@ -1,25 +1,29 @@
1
1
  <script lang="ts">
2
- import { ContextMenu as ContextMenuPrimitive } from "bits-ui";
3
- import { cn } from "../../../utils.js";
2
+ import { ContextMenu as ContextMenuPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
+ import { resolveOverlayPortalTarget } from "../../../utils/overlayPortalTarget.js";
4
5
 
5
- let {
6
- ref = $bindable(null),
7
- portalProps,
8
- class: className,
9
- ...restProps
10
- }: ContextMenuPrimitive.ContentProps & {
11
- portalProps?: ContextMenuPrimitive.PortalProps;
12
- } = $props();
6
+ let {
7
+ ref = $bindable(null),
8
+ portalProps,
9
+ class: className,
10
+ ...restProps
11
+ }: ContextMenuPrimitive.ContentProps & {
12
+ portalProps?: ContextMenuPrimitive.PortalProps;
13
+ } = $props();
13
14
  </script>
14
15
 
15
- <ContextMenuPrimitive.Portal {...portalProps}>
16
- <ContextMenuPrimitive.Content
17
- bind:ref
18
- data-slot="context-menu-content"
19
- class={cn(
20
- "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 max-h-(--bits-context-menu-content-available-height) origin-(--bits-context-menu-content-transform-origin) z-50 min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border p-1 shadow-md",
21
- className
22
- )}
23
- {...restProps}
24
- />
16
+ <ContextMenuPrimitive.Portal
17
+ {...portalProps}
18
+ to={portalProps?.to ?? resolveOverlayPortalTarget()}
19
+ >
20
+ <ContextMenuPrimitive.Content
21
+ bind:ref
22
+ data-slot="context-menu-content"
23
+ class={cn(
24
+ "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 max-h-(--bits-context-menu-content-available-height) origin-(--bits-context-menu-content-transform-origin) z-[100] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border p-1 shadow-md",
25
+ className,
26
+ )}
27
+ {...restProps}
28
+ />
25
29
  </ContextMenuPrimitive.Portal>
@@ -1,20 +1,20 @@
1
1
  <script lang="ts">
2
- import { ContextMenu as ContextMenuPrimitive } from "bits-ui";
3
- import { cn } from "../../../utils.js";
2
+ import { ContextMenu as ContextMenuPrimitive } from "bits-ui";
3
+ import { cn } from "../../../utils.js";
4
4
 
5
- let {
6
- ref = $bindable(null),
7
- class: className,
8
- ...restProps
9
- }: ContextMenuPrimitive.SubContentProps = $props();
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: ContextMenuPrimitive.SubContentProps = $props();
10
10
  </script>
11
11
 
12
12
  <ContextMenuPrimitive.SubContent
13
- bind:ref
14
- data-slot="context-menu-sub-content"
15
- class={cn(
16
- "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--bits-context-menu-content-transform-origin) z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg",
17
- className
18
- )}
19
- {...restProps}
13
+ bind:ref
14
+ data-slot="context-menu-sub-content"
15
+ class={cn(
16
+ "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--bits-context-menu-content-transform-origin) z-[100] min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg",
17
+ className,
18
+ )}
19
+ {...restProps}
20
20
  />
@@ -1,27 +1,31 @@
1
1
  <script lang="ts">
2
- import { cn } from "../../../utils.js";
3
- import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
2
+ import { cn } from "../../../utils.js";
3
+ import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
4
+ import { resolveOverlayPortalTarget } from "../../../utils/overlayPortalTarget.js";
4
5
 
5
- let {
6
- ref = $bindable(null),
7
- sideOffset = 4,
8
- portalProps,
9
- class: className,
10
- ...restProps
11
- }: DropdownMenuPrimitive.ContentProps & {
12
- portalProps?: DropdownMenuPrimitive.PortalProps;
13
- } = $props();
6
+ let {
7
+ ref = $bindable(null),
8
+ sideOffset = 4,
9
+ portalProps,
10
+ class: className,
11
+ ...restProps
12
+ }: DropdownMenuPrimitive.ContentProps & {
13
+ portalProps?: DropdownMenuPrimitive.PortalProps;
14
+ } = $props();
14
15
  </script>
15
16
 
16
- <DropdownMenuPrimitive.Portal {...portalProps}>
17
- <DropdownMenuPrimitive.Content
18
- bind:ref
19
- data-slot="dropdown-menu-content"
20
- {sideOffset}
21
- class={cn(
22
- "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 max-h-(--bits-dropdown-menu-content-available-height) origin-(--bits-dropdown-menu-content-transform-origin) z-50 min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border p-1 shadow-md outline-none",
23
- className
24
- )}
25
- {...restProps}
26
- />
17
+ <DropdownMenuPrimitive.Portal
18
+ {...portalProps}
19
+ to={portalProps?.to ?? resolveOverlayPortalTarget()}
20
+ >
21
+ <DropdownMenuPrimitive.Content
22
+ bind:ref
23
+ data-slot="dropdown-menu-content"
24
+ {sideOffset}
25
+ class={cn(
26
+ "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 max-h-(--bits-dropdown-menu-content-available-height) origin-(--bits-dropdown-menu-content-transform-origin) z-[100] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border p-1 shadow-md outline-none",
27
+ className,
28
+ )}
29
+ {...restProps}
30
+ />
27
31
  </DropdownMenuPrimitive.Portal>
@@ -1,3 +1,3 @@
1
1
  import Root from "./toggle.svelte";
2
- export { toggleVariants, type ToggleSize, type ToggleVariant, type ToggleVariants, } from "./toggle.svelte";
2
+ export { toggleVariants, type ToggleSize, type ToggleVariant, type ToggleVariants, } from "./toggle-variants.js";
3
3
  export { Root, Root as Toggle, };
@@ -1,5 +1,5 @@
1
1
  import Root from "./toggle.svelte";
2
- export { toggleVariants, } from "./toggle.svelte";
2
+ export { toggleVariants, } from "./toggle-variants.js";
3
3
  export { Root,
4
4
  //
5
5
  Root as Toggle, };
@@ -0,0 +1,35 @@
1
+ import { type VariantProps } from "tailwind-variants";
2
+ export declare const toggleVariants: import("tailwind-variants").TVReturnType<{
3
+ variant: {
4
+ default: string;
5
+ outline: string;
6
+ };
7
+ size: {
8
+ default: string;
9
+ sm: string;
10
+ lg: string;
11
+ };
12
+ }, undefined, "hover:text-foreground aria-pressed:bg-muted focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[state=on]:bg-muted gap-1 rounded-lg text-sm font-medium transition-all [&_svg:not([class*='size-'])]:size-4 group/toggle hover:bg-muted inline-flex items-center justify-center whitespace-nowrap outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0", {
13
+ variant: {
14
+ default: string;
15
+ outline: string;
16
+ };
17
+ size: {
18
+ default: string;
19
+ sm: string;
20
+ lg: string;
21
+ };
22
+ }, undefined, import("tailwind-variants").TVReturnType<{
23
+ variant: {
24
+ default: string;
25
+ outline: string;
26
+ };
27
+ size: {
28
+ default: string;
29
+ sm: string;
30
+ lg: string;
31
+ };
32
+ }, undefined, "hover:text-foreground aria-pressed:bg-muted focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[state=on]:bg-muted gap-1 rounded-lg text-sm font-medium transition-all [&_svg:not([class*='size-'])]:size-4 group/toggle hover:bg-muted inline-flex items-center justify-center whitespace-nowrap outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0", unknown, unknown, undefined>>;
33
+ export type ToggleVariant = VariantProps<typeof toggleVariants>["variant"];
34
+ export type ToggleSize = VariantProps<typeof toggleVariants>["size"];
35
+ export type ToggleVariants = VariantProps<typeof toggleVariants>;
@@ -0,0 +1,19 @@
1
+ import { tv } from "tailwind-variants";
2
+ export const toggleVariants = tv({
3
+ base: "hover:text-foreground aria-pressed:bg-muted focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[state=on]:bg-muted gap-1 rounded-lg text-sm font-medium transition-all [&_svg:not([class*='size-'])]:size-4 group/toggle hover:bg-muted inline-flex items-center justify-center whitespace-nowrap outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
4
+ variants: {
5
+ variant: {
6
+ default: "bg-transparent",
7
+ outline: "border-input hover:bg-muted border bg-transparent",
8
+ },
9
+ size: {
10
+ default: "h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
11
+ sm: "h-7 min-w-7 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
12
+ lg: "h-9 min-w-9 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
13
+ },
14
+ },
15
+ defaultVariants: {
16
+ variant: "default",
17
+ size: "default",
18
+ },
19
+ });