@leavepulse/ui 0.12.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 (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -0
  3. package/dist/component-names.d.ts +1 -0
  4. package/dist/components/LayoutCanvas.vue.d.ts +28 -0
  5. package/dist/components/LayoutNode.vue.d.ts +40 -0
  6. package/dist/components/LpAlert.vue.d.ts +44 -0
  7. package/dist/components/LpAppShell.vue.d.ts +83 -0
  8. package/dist/components/LpAutocomplete.vue.d.ts +50 -0
  9. package/dist/components/LpAvatar.vue.d.ts +20 -0
  10. package/dist/components/LpBadge.vue.d.ts +47 -0
  11. package/dist/components/LpBreadcrumbs.vue.d.ts +14 -0
  12. package/dist/components/LpButton.vue.d.ts +113 -0
  13. package/dist/components/LpCalendar.vue.d.ts +20 -0
  14. package/dist/components/LpCard.vue.d.ts +29 -0
  15. package/dist/components/LpCheckbox.vue.d.ts +28 -0
  16. package/dist/components/LpCodeBlock.vue.d.ts +39 -0
  17. package/dist/components/LpCommandPalette.vue.d.ts +42 -0
  18. package/dist/components/LpConfirmDialog.vue.d.ts +32 -0
  19. package/dist/components/LpContextMenu.vue.d.ts +30 -0
  20. package/dist/components/LpDatePicker.vue.d.ts +25 -0
  21. package/dist/components/LpDisclosure.vue.d.ts +37 -0
  22. package/dist/components/LpDivider.vue.d.ts +17 -0
  23. package/dist/components/LpDrawer.vue.d.ts +88 -0
  24. package/dist/components/LpDropdownMenu.vue.d.ts +23 -0
  25. package/dist/components/LpEmptyState.vue.d.ts +18 -0
  26. package/dist/components/LpFormField.vue.d.ts +21 -0
  27. package/dist/components/LpIcon.vue.d.ts +8 -0
  28. package/dist/components/LpInfraNode.vue.d.ts +21 -0
  29. package/dist/components/LpInput.vue.d.ts +68 -0
  30. package/dist/components/LpLaneNode.vue.d.ts +24 -0
  31. package/dist/components/LpLink.vue.d.ts +27 -0
  32. package/dist/components/LpLogViewer.vue.d.ts +92 -0
  33. package/dist/components/LpModal.vue.d.ts +43 -0
  34. package/dist/components/LpNotificationBell.vue.d.ts +51 -0
  35. package/dist/components/LpNumberField.vue.d.ts +14 -0
  36. package/dist/components/LpOtpInput.vue.d.ts +27 -0
  37. package/dist/components/LpPagination.vue.d.ts +25 -0
  38. package/dist/components/LpPasswordInput.vue.d.ts +28 -0
  39. package/dist/components/LpPhoneInput.vue.d.ts +37 -0
  40. package/dist/components/LpPopover.vue.d.ts +34 -0
  41. package/dist/components/LpProgress.vue.d.ts +12 -0
  42. package/dist/components/LpRadio.vue.d.ts +18 -0
  43. package/dist/components/LpRadioGroup.vue.d.ts +26 -0
  44. package/dist/components/LpScrollArea.vue.d.ts +24 -0
  45. package/dist/components/LpSegmented.vue.d.ts +24 -0
  46. package/dist/components/LpSelect.vue.d.ts +45 -0
  47. package/dist/components/LpServiceNode.vue.d.ts +14 -0
  48. package/dist/components/LpSidebar.vue.d.ts +85 -0
  49. package/dist/components/LpSidebarNav.vue.d.ts +34 -0
  50. package/dist/components/LpSkeleton.vue.d.ts +6 -0
  51. package/dist/components/LpSlider.vue.d.ts +23 -0
  52. package/dist/components/LpStat.vue.d.ts +22 -0
  53. package/dist/components/LpStepper.vue.d.ts +10 -0
  54. package/dist/components/LpSwitch.vue.d.ts +11 -0
  55. package/dist/components/LpTable.vue.d.ts +63 -0
  56. package/dist/components/LpTableOfContents.vue.d.ts +19 -0
  57. package/dist/components/LpTabs.vue.d.ts +45 -0
  58. package/dist/components/LpTextarea.vue.d.ts +17 -0
  59. package/dist/components/LpThemeSwitcher.vue.d.ts +40 -0
  60. package/dist/components/LpToaster.vue.d.ts +3 -0
  61. package/dist/components/LpTooltip.vue.d.ts +19 -0
  62. package/dist/components/LpTopologyCanvas.vue.d.ts +154 -0
  63. package/dist/components/LpUptimeBar.vue.d.ts +30 -0
  64. package/dist/components/codeHighlight.d.ts +8 -0
  65. package/dist/components/countries-data.d.ts +2 -0
  66. package/dist/components/countries.d.ts +20 -0
  67. package/dist/components/dropdown.d.ts +29 -0
  68. package/dist/components/sidebar.d.ts +18 -0
  69. package/dist/composables/useInputFilter.d.ts +14 -0
  70. package/dist/composables/usePillTransition.d.ts +9 -0
  71. package/dist/composables/useToast.d.ts +39 -0
  72. package/dist/countries-data-9rgqJWHo.js +203 -0
  73. package/dist/icons.d.ts +1 -0
  74. package/dist/index.css +1 -0
  75. package/dist/index.d.ts +100 -0
  76. package/dist/index.js +17600 -0
  77. package/dist/layout/registry.d.ts +26 -0
  78. package/dist/layout/tree.d.ts +75 -0
  79. package/dist/layout/useLayout.d.ts +39 -0
  80. package/dist/theme/config.d.ts +16 -0
  81. package/dist/theme/define.d.ts +12 -0
  82. package/dist/theme/presets.d.ts +20 -0
  83. package/dist/theme/tokens.d.ts +72 -0
  84. package/dist/theme/useTheme.d.ts +36 -0
  85. package/package.json +93 -0
  86. package/src/canvas.css +67 -0
  87. package/src/component-names.ts +65 -0
  88. package/src/components/LayoutCanvas.vue +76 -0
  89. package/src/components/LayoutNode.vue +248 -0
  90. package/src/components/LpAlert.vue +59 -0
  91. package/src/components/LpAppShell.vue +210 -0
  92. package/src/components/LpAutocomplete.vue +244 -0
  93. package/src/components/LpAvatar.vue +67 -0
  94. package/src/components/LpBadge.vue +32 -0
  95. package/src/components/LpBreadcrumbs.vue +35 -0
  96. package/src/components/LpButton.vue +111 -0
  97. package/src/components/LpCalendar.vue +134 -0
  98. package/src/components/LpCard.vue +71 -0
  99. package/src/components/LpCheckbox.vue +44 -0
  100. package/src/components/LpCodeBlock.vue +298 -0
  101. package/src/components/LpCommandPalette.vue +323 -0
  102. package/src/components/LpConfirmDialog.vue +49 -0
  103. package/src/components/LpContextMenu.vue +111 -0
  104. package/src/components/LpDatePicker.vue +117 -0
  105. package/src/components/LpDisclosure.vue +92 -0
  106. package/src/components/LpDivider.vue +20 -0
  107. package/src/components/LpDrawer.vue +402 -0
  108. package/src/components/LpDropdownMenu.vue +54 -0
  109. package/src/components/LpEmptyState.vue +21 -0
  110. package/src/components/LpFormField.vue +31 -0
  111. package/src/components/LpIcon.vue +49 -0
  112. package/src/components/LpInfraNode.vue +108 -0
  113. package/src/components/LpInput.vue +147 -0
  114. package/src/components/LpLaneNode.vue +48 -0
  115. package/src/components/LpLink.vue +48 -0
  116. package/src/components/LpLogViewer.vue +569 -0
  117. package/src/components/LpModal.vue +123 -0
  118. package/src/components/LpNotificationBell.vue +238 -0
  119. package/src/components/LpNumberField.vue +56 -0
  120. package/src/components/LpOtpInput.vue +81 -0
  121. package/src/components/LpPagination.vue +165 -0
  122. package/src/components/LpPasswordInput.vue +50 -0
  123. package/src/components/LpPhoneInput.vue +241 -0
  124. package/src/components/LpPopover.vue +42 -0
  125. package/src/components/LpProgress.vue +30 -0
  126. package/src/components/LpRadio.vue +28 -0
  127. package/src/components/LpRadioGroup.vue +43 -0
  128. package/src/components/LpScrollArea.vue +82 -0
  129. package/src/components/LpSegmented.vue +83 -0
  130. package/src/components/LpSelect.vue +0 -0
  131. package/src/components/LpServiceNode.vue +57 -0
  132. package/src/components/LpSidebar.vue +200 -0
  133. package/src/components/LpSidebarNav.vue +118 -0
  134. package/src/components/LpSkeleton.vue +16 -0
  135. package/src/components/LpSlider.vue +53 -0
  136. package/src/components/LpStat.vue +90 -0
  137. package/src/components/LpStepper.vue +46 -0
  138. package/src/components/LpSwitch.vue +19 -0
  139. package/src/components/LpTable.vue +252 -0
  140. package/src/components/LpTableOfContents.vue +183 -0
  141. package/src/components/LpTabs.vue +120 -0
  142. package/src/components/LpTextarea.vue +39 -0
  143. package/src/components/LpThemeSwitcher.vue +168 -0
  144. package/src/components/LpToaster.vue +216 -0
  145. package/src/components/LpTooltip.vue +30 -0
  146. package/src/components/LpTopologyCanvas.vue +370 -0
  147. package/src/components/LpUptimeBar.vue +126 -0
  148. package/src/components/codeHighlight.ts +137 -0
  149. package/src/components/countries-data.ts +207 -0
  150. package/src/components/countries.ts +67 -0
  151. package/src/components/dropdown.ts +64 -0
  152. package/src/components/sidebar.ts +26 -0
  153. package/src/composables/useInputFilter.ts +89 -0
  154. package/src/composables/usePillTransition.ts +19 -0
  155. package/src/composables/useToast.ts +92 -0
  156. package/src/icons.ts +11 -0
  157. package/src/index.css +21 -0
  158. package/src/index.ts +146 -0
  159. package/src/layout/registry.ts +44 -0
  160. package/src/layout/tree.ts +288 -0
  161. package/src/layout/useLayout.ts +134 -0
  162. package/src/nuxt.ts +22 -0
  163. package/src/theme/config.ts +48 -0
  164. package/src/theme/define.ts +50 -0
  165. package/src/theme/presets.ts +279 -0
  166. package/src/theme/tokens.ts +151 -0
  167. package/src/theme/useTheme.ts +288 -0
  168. package/src/tokens/scrollbar.css +138 -0
  169. package/src/tokens/tokens.css +333 -0
  170. package/src/tokens/utilities.css +23 -0
@@ -0,0 +1,26 @@
1
+ import { Component } from 'vue';
2
+ export interface BlockDef {
3
+ /**
4
+ * Content component for this block. Optional: when the consumer renders block
5
+ * content via the canvas's #block slot (keyed by id), the registry is used
6
+ * only for tab chrome (title/icon) and no component is needed here.
7
+ */
8
+ component?: Component;
9
+ /** Human label shown on the tab / cell header. Defaults to the id. */
10
+ title?: string;
11
+ /** Optional iconify name (e.g. "lucide:activity") for the tab. */
12
+ icon?: string;
13
+ /** Whether the user may close this block. Defaults to true. */
14
+ closable?: boolean;
15
+ /** Props passed to the component. */
16
+ props?: Record<string, unknown>;
17
+ }
18
+ export type BlockRegistry = Record<string, BlockDef>;
19
+ /**
20
+ * Identity helper that pins the key type so callers get autocomplete on block
21
+ * ids elsewhere (e.g. when seeding a layout). Purely for inference — it returns
22
+ * the object unchanged.
23
+ */
24
+ export declare function defineBlocks<const T extends BlockRegistry>(blocks: T): T;
25
+ /** Resolve a block's display title, falling back to its id. */
26
+ export declare function blockTitle(registry: BlockRegistry, id: string): string;
@@ -0,0 +1,75 @@
1
+ export type Dir = "row" | "col";
2
+ export type Side = "left" | "right" | "top" | "bottom" | "center";
3
+ export interface Leaf {
4
+ kind: "leaf";
5
+ id: string;
6
+ /**
7
+ * Block ids stacked as tabs in this cell. A plain cell is a single-element
8
+ * stack; dropping onto a cell's center adds another tab. The consumer maps
9
+ * each id to content via the canvas slot.
10
+ */
11
+ blocks: string[];
12
+ /** Index into `blocks` of the visible tab. */
13
+ active: number;
14
+ /** Flex fraction among siblings. */
15
+ size: number;
16
+ }
17
+ export interface Split {
18
+ kind: "split";
19
+ id: string;
20
+ dir: Dir;
21
+ size: number;
22
+ children: LayoutNode[];
23
+ }
24
+ export type LayoutNode = Leaf | Split;
25
+ /** Build a single-row layout from a flat list of block ids (one cell each). */
26
+ export declare function makeLayout(blocks: string[]): Split;
27
+ export declare function findParent(node: Split, childId: string): Split | null;
28
+ export declare function findLeaf(node: LayoutNode, id: string): Leaf | null;
29
+ export declare function countLeaves(node: LayoutNode): number;
30
+ /** Total blocks across all cells (a tabbed cell counts each of its tabs). */
31
+ export declare function countBlocks(node: LayoutNode): number;
32
+ /** Remove an entire cell (with all its tabs). */
33
+ export declare function removeLeaf(root: Split, id: string): void;
34
+ /**
35
+ * Remove one tab from a cell. Removing the last tab removes the cell itself
36
+ * (unless it's the only block left in the whole layout, which is kept).
37
+ */
38
+ export declare function removeBlock(root: Split, leafId: string, index: number): void;
39
+ export declare function addLeaf(root: Split, block: string, side?: Side): void;
40
+ /** Append a block as a new tab in the target cell and focus it. */
41
+ export declare function addTab(root: Split, leafId: string, block: string): void;
42
+ /** Switch the visible tab of a cell. */
43
+ export declare function setActiveTab(root: Split, leafId: string, index: number): void;
44
+ /**
45
+ * Reorder a tab within its cell, moving the block at `from` to `to`. The same
46
+ * block stays visible afterwards (active follows the moved block by identity,
47
+ * not by index). Always available — not gated by edit mode.
48
+ */
49
+ export declare function reorderTab(root: Split, leafId: string, from: number, to: number): void;
50
+ /**
51
+ * Move an existing cell to a target. An edge side splits beside the target;
52
+ * `center` merges the moving cell's tabs into the target cell (and focuses
53
+ * the first moved tab).
54
+ */
55
+ export declare function moveLeaf(root: Split, movingId: string, targetId: string, side: Side): void;
56
+ /** Splitter drag: redistribute size between two adjacent siblings. */
57
+ export declare function resizeAt(parent: Split, index: number, deltaFraction: number): void;
58
+ interface SerializedLeaf {
59
+ kind: "leaf";
60
+ blocks: string[];
61
+ active: number;
62
+ size: number;
63
+ /** Legacy single-block form (pre-tabs); hydrated into `blocks`. */
64
+ block?: string;
65
+ }
66
+ interface SerializedSplit {
67
+ kind: "split";
68
+ dir: Dir;
69
+ size: number;
70
+ children: SerializedNode[];
71
+ }
72
+ type SerializedNode = SerializedLeaf | SerializedSplit;
73
+ export declare function serializeLayout(root: Split): SerializedNode;
74
+ export declare function deserializeLayout(data: SerializedNode): Split;
75
+ export {};
@@ -0,0 +1,39 @@
1
+ import { Ref } from 'vue';
2
+ import { Side, Split } from './tree';
3
+ export interface UseLayoutOptions {
4
+ /** Initial block ids, left-to-right, when no saved layout is loaded. */
5
+ initial: string[];
6
+ /** Max undo depth. */
7
+ historyLimit?: number;
8
+ }
9
+ export interface UseLayout {
10
+ /** The live reactive tree to hand to <LayoutCanvas v-model>. */
11
+ layout: Ref<Split>;
12
+ /** Block count across all tabs, handy for "N blocks" labels and guards. */
13
+ count: Ref<number>;
14
+ canUndo: Ref<boolean>;
15
+ canRedo: Ref<boolean>;
16
+ /** Add a block: a new cell on an edge, or a tab on the last cell (center). */
17
+ add: (block: string, side?: Side) => void;
18
+ /** Add a block as a tab in a specific cell. */
19
+ addTab: (leafId: string, block: string) => void;
20
+ /** Switch the visible tab of a cell. */
21
+ setActive: (leafId: string, index: number) => void;
22
+ /** Reorder a tab within its cell (always available, not edit-gated). */
23
+ reorderTab: (leafId: string, from: number, to: number) => void;
24
+ /** Remove one tab (drops the cell when it was the last tab). */
25
+ removeBlock: (leafId: string, index: number) => void;
26
+ /** Remove an entire cell with all its tabs. */
27
+ remove: (leafId: string) => void;
28
+ move: (movingId: string, targetId: string, side: Side) => void;
29
+ resize: (parent: Split, index: number, deltaFraction: number) => void;
30
+ undo: () => void;
31
+ redo: () => void;
32
+ /** Replace the whole layout from a flat block list. */
33
+ reset: (blocks?: string[]) => void;
34
+ /** Serialize to JSON-safe data for persistence. */
35
+ serialize: () => unknown;
36
+ /** Replace the layout from previously serialized data. */
37
+ hydrate: (data: unknown) => void;
38
+ }
39
+ export declare function useLayout(options: UseLayoutOptions): UseLayout;
@@ -0,0 +1,16 @@
1
+ import { Split } from '../layout/tree';
2
+ import { TokenSet } from './tokens';
3
+ export declare const UI_CONFIG_VERSION = 1;
4
+ export interface UiConfig {
5
+ version: number;
6
+ theme: TokenSet;
7
+ /** Optional — apps without a composable layout omit it. */
8
+ layout?: Split;
9
+ }
10
+ export interface SerializedUiConfig {
11
+ version: number;
12
+ theme: TokenSet;
13
+ layout?: unknown;
14
+ }
15
+ export declare function serializeConfig(config: UiConfig): string;
16
+ export declare function parseConfig(json: string): UiConfig;
@@ -0,0 +1,12 @@
1
+ import { presets } from './presets';
2
+ import { ColorTokens, DensityTokens, FontTokens, ShapeTokens, SurfaceTokens, TokenSet } from './tokens';
3
+ export interface ThemeOverrides {
4
+ name?: string;
5
+ mode?: "dark" | "light";
6
+ colors?: Partial<ColorTokens>;
7
+ shape?: Partial<ShapeTokens>;
8
+ density?: Partial<DensityTokens>;
9
+ font?: Partial<FontTokens>;
10
+ surface?: Partial<SurfaceTokens>;
11
+ }
12
+ export declare function defineTheme(base: TokenSet | keyof typeof presets, overrides?: ThemeOverrides): TokenSet;
@@ -0,0 +1,20 @@
1
+ import { TokenSet } from './tokens';
2
+ export declare const dark: TokenSet;
3
+ export declare const light: TokenSet;
4
+ export declare const lime: TokenSet;
5
+ export declare const leavepulse: TokenSet;
6
+ export declare const rose: TokenSet;
7
+ export declare const amber: TokenSet;
8
+ export declare const violet: TokenSet;
9
+ export declare const nord: TokenSet;
10
+ export declare const presets: {
11
+ readonly dark: TokenSet;
12
+ readonly light: TokenSet;
13
+ readonly lime: TokenSet;
14
+ readonly leavepulse: TokenSet;
15
+ readonly rose: TokenSet;
16
+ readonly amber: TokenSet;
17
+ readonly violet: TokenSet;
18
+ readonly nord: TokenSet;
19
+ };
20
+ export type PresetName = keyof typeof presets;
@@ -0,0 +1,72 @@
1
+ export interface ColorTokens {
2
+ surface: string;
3
+ surfaceRaised: string;
4
+ surfaceSoft: string;
5
+ ink: string;
6
+ inkInverse: string;
7
+ muted: string;
8
+ mutedStrong: string;
9
+ brand: string;
10
+ brandHover: string;
11
+ brandSoft: string;
12
+ action: string;
13
+ actionHover: string;
14
+ accent: string;
15
+ danger: string;
16
+ dangerHover: string;
17
+ dangerSoft: string;
18
+ line: string;
19
+ lineStrong: string;
20
+ ring: string;
21
+ }
22
+ export interface ShapeTokens {
23
+ radiusControl: number;
24
+ radiusCard: number;
25
+ radiusPill: number;
26
+ }
27
+ export interface DensityTokens {
28
+ /** base spacing unit in px */
29
+ spacingUnit: number;
30
+ controlSm: number;
31
+ controlMd: number;
32
+ controlLg: number;
33
+ }
34
+ export interface FontTokens {
35
+ /** CSS font-family stack for UI text */
36
+ sans: string;
37
+ /** CSS font-family stack for numerals / code */
38
+ mono: string;
39
+ }
40
+ export interface SurfaceTokens {
41
+ /** Border width for panels/cards/controls (CSS length, e.g. "1px"). */
42
+ borderWidth: string;
43
+ /** backdrop-filter blur radius (CSS length; "0" disables glass blur). */
44
+ panelBlur: string;
45
+ /** backdrop-filter saturate (unitless or %, e.g. "100%" / "180%"). */
46
+ panelSaturate: string;
47
+ /** Overlay painted over a panel's base color ("none" or a gradient). */
48
+ panelOverlay: string;
49
+ /** Box-shadow for a raised panel (may be multi-layer for glass). */
50
+ panelShadow: string;
51
+ /** Inset highlight line for a panel ("none" or an inset box-shadow). */
52
+ panelInset: string;
53
+ }
54
+ export interface TokenSet {
55
+ /** human label, e.g. "Lime" */
56
+ name: string;
57
+ /** "dark" | "light" — drives `color-scheme` and the data-theme-mode hint */
58
+ mode: "dark" | "light";
59
+ colors: ColorTokens;
60
+ shape: ShapeTokens;
61
+ density: DensityTokens;
62
+ font: FontTokens;
63
+ /** Optional skin axis; older themes without it fall back to a flat default. */
64
+ surface?: SurfaceTokens;
65
+ }
66
+ /** camelCase token key → CSS custom property name. */
67
+ export declare const COLOR_VARS: Record<keyof ColorTokens, string>;
68
+ export declare const SHAPE_VARS: Record<keyof ShapeTokens, string>;
69
+ export declare const DENSITY_VARS: Record<keyof DensityTokens, string>;
70
+ export declare const FONT_VARS: Record<keyof FontTokens, string>;
71
+ export declare const SURFACE_VARS: Record<keyof SurfaceTokens, string>;
72
+ export declare const DEFAULT_SURFACE: SurfaceTokens;
@@ -0,0 +1,36 @@
1
+ import { ComputedRef, DeepReadonly, Ref } from 'vue';
2
+ import { TokenSet } from './tokens';
3
+ export declare function applyTheme(theme: TokenSet, root?: HTMLElement): void;
4
+ /** Point a circular theme reveal expands from (viewport px). */
5
+ export interface RevealOrigin {
6
+ x: number;
7
+ y: number;
8
+ }
9
+ export declare function applyThemeWithTransition(theme: TokenSet, origin?: RevealOrigin, root?: HTMLElement, durationMs?: number): void;
10
+ export declare function serializeTheme(theme: TokenSet): string;
11
+ export declare function themeToCssVars(theme: TokenSet): string;
12
+ /** Render a theme as a complete CSS rule (default selector `:root`). */
13
+ export declare function themeToCssRule(theme: TokenSet, selector?: string): string;
14
+ /** Parse + shallow-validate a theme JSON; throws on a malformed shape. */
15
+ export declare function parseTheme(json: string): TokenSet;
16
+ export declare function bootstrapTheme(fallback: TokenSet): TokenSet;
17
+ export declare function cacheTheme(theme: TokenSet): void;
18
+ export interface UseTheme {
19
+ /** The active theme, kept in sync by the kit. Null until hydrated (SSR/first
20
+ * paint) — reactive, so a switcher binds straight to it. */
21
+ current: DeepReadonly<Ref<TokenSet | null>>;
22
+ /** The active theme's name (""="not yet hydrated"). */
23
+ currentName: ComputedRef<string>;
24
+ /** Set + persist a theme (with the circular reveal if `origin`/transition).
25
+ * This is the one call a switcher needs — it updates `current` too. */
26
+ setTheme: (theme: TokenSet, origin?: RevealOrigin) => void;
27
+ /** Seed the fallback (used when nothing is cached) and hydrate now. Call once
28
+ * at app start (client) — optional; the first useTheme() hydrates anyway. */
29
+ init: (fallback: TokenSet) => TokenSet;
30
+ apply: (theme: TokenSet) => void;
31
+ applyWithTransition: (theme: TokenSet, origin?: RevealOrigin) => void;
32
+ serialize: typeof serializeTheme;
33
+ parse: typeof parseTheme;
34
+ bootstrap: typeof bootstrapTheme;
35
+ }
36
+ export declare function useTheme(): UseTheme;
package/package.json ADDED
@@ -0,0 +1,93 @@
1
+ {
2
+ "name": "@leavepulse/ui",
3
+ "version": "0.12.0",
4
+ "type": "module",
5
+ "description": "LeavePulse token-driven Vue component kit.",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/LeavePulse/leavepulse-ui.git"
9
+ },
10
+ "license": "MIT",
11
+ "files": [
12
+ "dist",
13
+ "src"
14
+ ],
15
+ "main": "./dist/index.js",
16
+ "module": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "style": "./src/index.css",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "style": "./src/index.css",
23
+ "import": "./dist/index.js"
24
+ },
25
+ "./nuxt": "./src/nuxt.ts",
26
+ "./css": "./src/index.css",
27
+ "./tokens.css": "./src/tokens/tokens.css",
28
+ "./scrollbar.css": "./src/tokens/scrollbar.css",
29
+ "./canvas.css": "./src/canvas.css"
30
+ },
31
+ "publishConfig": {
32
+ "registry": "https://npm.pkg.github.com"
33
+ },
34
+ "sideEffects": [
35
+ "**/*.css",
36
+ "**/icons.ts",
37
+ "**/icons.js"
38
+ ],
39
+ "scripts": {
40
+ "dev": "vite",
41
+ "gen:names": "node scripts/gen-component-names.mjs",
42
+ "build": "node scripts/gen-component-names.mjs && vue-tsc --noEmit -p tsconfig.build.json && vite build --config vite.lib.config.ts",
43
+ "dev:dist": "vite build --watch --config vite.lib.config.ts",
44
+ "prepublishOnly": "node scripts/gen-component-names.mjs && vue-tsc --noEmit -p tsconfig.build.json && vite build --config vite.lib.config.ts",
45
+ "typecheck": "vue-tsc --noEmit",
46
+ "release": "npm version patch -m \"chore: release v%s\" && git push --follow-tags",
47
+ "release:minor": "npm version minor -m \"chore: release v%s\" && git push --follow-tags",
48
+ "release:major": "npm version major -m \"chore: release v%s\" && git push --follow-tags"
49
+ },
50
+ "peerDependencies": {
51
+ "@iconify-json/lucide": "^1.2.0",
52
+ "@iconify/vue": "^5.0.0",
53
+ "@internationalized/date": "^3.5.0",
54
+ "@nuxt/kit": "^3.0.0 || ^4.0.0",
55
+ "@vueuse/core": "^12.0.0 || ^13.0.0 || ^14.0.0",
56
+ "motion-v": "^2.2.0",
57
+ "reka-ui": "^2.9.0",
58
+ "tailwind-merge": "^3.0.0",
59
+ "tailwind-variants": "^3.0.0",
60
+ "tailwindcss": "^4.0.0",
61
+ "vaul-vue": "^0.4.0",
62
+ "vue": "^3.5.0"
63
+ },
64
+ "peerDependenciesMeta": {
65
+ "@nuxt/kit": {
66
+ "optional": true
67
+ }
68
+ },
69
+ "devDependencies": {
70
+ "@iconify-json/lucide": "^1.2.112",
71
+ "@iconify/vue": "^5.0.1",
72
+ "@tailwindcss/vite": "^4.2.4",
73
+ "@vitejs/plugin-vue": "^6.0.6",
74
+ "motion-v": "^2.2.1",
75
+ "reka-ui": "^2.9.10",
76
+ "shiki": "^4.2.0",
77
+ "tailwind-merge": "^3.6.0",
78
+ "tailwind-variants": "^3.2.2",
79
+ "tailwindcss": "^4.2.4",
80
+ "typescript": "^5.6.3",
81
+ "vite": "^7.0.0",
82
+ "vite-plugin-dts": "^5.0.2",
83
+ "vue": "3.5.31",
84
+ "vue-tsc": "^3.0.0"
85
+ },
86
+ "dependencies": {
87
+ "@vue-flow/background": "^1.3.2",
88
+ "@vue-flow/controls": "^1.1.3",
89
+ "@vue-flow/core": "^1.48.2",
90
+ "@vue-flow/minimap": "^1.5.4",
91
+ "vaul-vue": "^0.4.1"
92
+ }
93
+ }
package/src/canvas.css ADDED
@@ -0,0 +1,67 @@
1
+ /*
2
+ * LpTopologyCanvas styles — Vue Flow base CSS + kit-token chrome theming.
3
+ *
4
+ * Shipped as a standalone CSS file (the "@leavepulse/ui/canvas.css" export) so
5
+ * consuming apps get the Vue Flow base styles + canvas chrome with ONE import.
6
+ * Component-local CSS imports (`import "@vue-flow/core/dist/style.css"` inside a
7
+ * .vue) don't reach apps through the built dist, and scoped component styles
8
+ * aren't emitted by the consumer's Tailwind @source either — so canvas styling
9
+ * lives here. App usage: @import "@leavepulse/ui/canvas.css";
10
+ */
11
+
12
+ @import "@vue-flow/core/dist/style.css";
13
+ @import "@vue-flow/core/dist/theme-default.css";
14
+ @import "@vue-flow/controls/dist/style.css";
15
+ @import "@vue-flow/minimap/dist/style.css";
16
+
17
+ .lp-topology {
18
+ background: var(--color-surface);
19
+ }
20
+
21
+ .lp-topology .vue-flow__controls {
22
+ box-shadow: var(--shadow-panel);
23
+ border-radius: var(--radius-control);
24
+ overflow: hidden;
25
+ }
26
+ .lp-topology .vue-flow__controls-button {
27
+ background: var(--color-surface-raised);
28
+ border-bottom: 1px solid var(--color-line);
29
+ fill: var(--color-muted-strong);
30
+ }
31
+ .lp-topology .vue-flow__controls-button:hover {
32
+ background: var(--color-surface-soft);
33
+ }
34
+ .lp-topology .vue-flow__minimap {
35
+ border-radius: var(--radius-card);
36
+ border: 1px solid var(--color-line);
37
+ overflow: hidden;
38
+ /* Vue Flow defaults the minimap to a white background; theme it. */
39
+ background-color: var(--color-surface-raised);
40
+ }
41
+ .lp-topology .vue-flow__minimap svg {
42
+ background-color: var(--color-surface-raised);
43
+ }
44
+ /* The dimmed area outside the current viewport. */
45
+ .lp-topology .vue-flow__minimap-mask {
46
+ fill: color-mix(in srgb, var(--color-surface) 70%, transparent);
47
+ }
48
+ .lp-topology .vue-flow__edge-text {
49
+ fill: var(--color-muted-strong);
50
+ }
51
+ .lp-topology .vue-flow__edge-textbg {
52
+ fill: var(--color-surface);
53
+ }
54
+
55
+ /* Host-frame (group node) title. Vue Flow's default group label is a dim,
56
+ centered grey that's nearly invisible on the dark surface — pin it to the
57
+ top-left of the frame and use the ink token so host names (proxy-vps,
58
+ app-vps-1, …) read clearly. */
59
+ .lp-topology .vue-flow__node-group {
60
+ display: flex;
61
+ align-items: flex-start;
62
+ justify-content: flex-start;
63
+ padding: 8px 12px;
64
+ font-size: 12px;
65
+ font-weight: 600;
66
+ color: var(--color-ink);
67
+ }
@@ -0,0 +1,65 @@
1
+ /* AUTO-GENERATED by scripts/gen-component-names.mjs — do not edit.
2
+ * The full list of kit component names, kept in sync with the component files
3
+ * so the Nuxt module (./nuxt) auto-registers every component including new ones. */
4
+ export const COMPONENT_NAMES = [
5
+ "LayoutCanvas",
6
+ "LayoutNode",
7
+ "LpAlert",
8
+ "LpAppShell",
9
+ "LpAutocomplete",
10
+ "LpAvatar",
11
+ "LpBadge",
12
+ "LpBreadcrumbs",
13
+ "LpButton",
14
+ "LpCalendar",
15
+ "LpCard",
16
+ "LpCheckbox",
17
+ "LpCodeBlock",
18
+ "LpCommandPalette",
19
+ "LpConfirmDialog",
20
+ "LpContextMenu",
21
+ "LpDatePicker",
22
+ "LpDisclosure",
23
+ "LpDivider",
24
+ "LpDrawer",
25
+ "LpDropdownMenu",
26
+ "LpEmptyState",
27
+ "LpFormField",
28
+ "LpIcon",
29
+ "LpInfraNode",
30
+ "LpInput",
31
+ "LpLaneNode",
32
+ "LpLink",
33
+ "LpLogViewer",
34
+ "LpModal",
35
+ "LpNotificationBell",
36
+ "LpNumberField",
37
+ "LpOtpInput",
38
+ "LpPagination",
39
+ "LpPasswordInput",
40
+ "LpPhoneInput",
41
+ "LpPopover",
42
+ "LpProgress",
43
+ "LpRadio",
44
+ "LpRadioGroup",
45
+ "LpScrollArea",
46
+ "LpSegmented",
47
+ "LpSelect",
48
+ "LpServiceNode",
49
+ "LpSidebar",
50
+ "LpSidebarNav",
51
+ "LpSkeleton",
52
+ "LpSlider",
53
+ "LpStat",
54
+ "LpStepper",
55
+ "LpSwitch",
56
+ "LpTable",
57
+ "LpTableOfContents",
58
+ "LpTabs",
59
+ "LpTextarea",
60
+ "LpThemeSwitcher",
61
+ "LpToaster",
62
+ "LpTooltip",
63
+ "LpTopologyCanvas",
64
+ "LpUptimeBar"
65
+ ] as const
@@ -0,0 +1,76 @@
1
+ <script setup lang="ts">
2
+ /*
3
+ * LayoutCanvas — a user-composable block layout.
4
+ *
5
+ * Renders a layout tree (v-model) of cells. Each cell is a tab stack of blocks.
6
+ * In `edit` mode the user can drag a cell onto another cell's edge to split,
7
+ * drop on the center to merge as tabs, drag dividers to resize, switch tabs,
8
+ * and close tabs. Block content is supplied through the `#block` scoped slot,
9
+ * keyed by the block id stored in the tree — the canvas owns geometry + chrome,
10
+ * the consumer owns content. Pass a `registry` for tab titles/icons.
11
+ *
12
+ * The tree is plain serializable data (see layout/tree.ts).
13
+ */
14
+ import LayoutNode from "./LayoutNode.vue"
15
+ import {
16
+ moveLeaf,
17
+ removeBlock,
18
+ reorderTab,
19
+ resizeAt,
20
+ setActiveTab,
21
+ type Side,
22
+ type Split,
23
+ } from "../layout/tree"
24
+ import type { BlockRegistry } from "../layout/registry"
25
+ import { ref } from "vue"
26
+
27
+ const props = defineProps<{
28
+ modelValue: Split
29
+ edit?: boolean
30
+ /** Catalogue mapping block ids to titles/icons for the tab bars. */
31
+ registry?: BlockRegistry
32
+ }>()
33
+
34
+ // modelValue is a reactive tree we mutate in place; no emit needed for
35
+ // structural changes, but we keep the v-model contract for replacement
36
+ // (e.g. load-from-disk swaps the whole tree).
37
+ defineEmits<{ (e: "update:modelValue", value: Split): void }>()
38
+
39
+ defineSlots<{
40
+ block(props: { block: string; leafId: string; edit: boolean }): unknown
41
+ }>()
42
+
43
+ const dragId = ref<string | null>(null)
44
+
45
+ function onDrop(targetId: string, side: Side) {
46
+ if (dragId.value) moveLeaf(props.modelValue, dragId.value, targetId, side)
47
+ dragId.value = null
48
+ }
49
+
50
+ function onResize(parent: Split, index: number, delta: number) {
51
+ resizeAt(parent, index, delta)
52
+ }
53
+ </script>
54
+
55
+ <template>
56
+ <div class="flex min-h-0 min-w-0 flex-1">
57
+ <LayoutNode
58
+ :node="modelValue"
59
+ :drag-id="dragId"
60
+ :edit="!!edit"
61
+ :registry="registry"
62
+ class="flex-1"
63
+ @dragstart="(id) => (dragId = id)"
64
+ @dragend="dragId = null"
65
+ @drop="onDrop"
66
+ @set-active="(leafId, i) => setActiveTab(modelValue, leafId, i)"
67
+ @remove-block="(leafId, i) => removeBlock(modelValue, leafId, i)"
68
+ @reorder-tab="(leafId, from, to) => reorderTab(modelValue, leafId, from, to)"
69
+ @resize="onResize"
70
+ >
71
+ <template #block="slotProps">
72
+ <slot name="block" v-bind="slotProps" />
73
+ </template>
74
+ </LayoutNode>
75
+ </div>
76
+ </template>