@runwisp/ui 1.0.0 → 1.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@runwisp/ui",
3
3
  "description": "Svelte 5 UI component library for RunWisp dashboards and admin interfaces.",
4
- "version": "1.0.0",
4
+ "version": "1.0.1",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -49,8 +49,8 @@
49
49
  "devDependencies": {
50
50
  "@chromatic-com/storybook": "^5.2.1",
51
51
  "@eslint/js": "^10.0.1",
52
- "@runwisp/eslint-config": "1.0.0",
53
- "@runwisp/typescript-config": "1.0.0",
52
+ "@runwisp/eslint-config": "1.0.1",
53
+ "@runwisp/typescript-config": "1.0.1",
54
54
  "@storybook/addon-a11y": "^10.5.5",
55
55
  "@storybook/addon-docs": "^10.5.5",
56
56
  "@storybook/addon-svelte-csf": "^5.1.2",
@@ -93,7 +93,7 @@
93
93
  "@fontsource-variable/geist-mono": "^5.3.0",
94
94
  "@fontsource/tasa-orbiter": "^5.3.0",
95
95
  "@lucide/svelte": "^1.28.0",
96
- "@runwisp/common": "1.0.0",
96
+ "@runwisp/common": "1.0.1",
97
97
  "@tanstack/svelte-virtual": "^3.13.35",
98
98
  "ansi-to-html": "^0.7.2",
99
99
  "cron-parser": "^5.7.0",
@@ -3,9 +3,11 @@
3
3
 
4
4
  <script lang="ts">
5
5
  import type { Snippet } from "svelte";
6
+ import Tooltip from "./Tooltip.svelte";
6
7
 
7
8
  type BadgeVariant = "default" | "primary" | "success" | "warning" | "danger" | "info";
8
9
  type BadgeSize = "sm" | "md" | "lg";
10
+ type TooltipPosition = "top" | "bottom" | "left" | "right";
9
11
 
10
12
  interface Props {
11
13
  variant?: BadgeVariant;
@@ -13,6 +15,10 @@
13
15
  dot?: boolean;
14
16
  loading?: boolean;
15
17
  outline?: boolean;
18
+ /** Shown in the styled hover tooltip (see {@link Tooltip}). */
19
+ tooltip?: string;
20
+ /** Side the tooltip opens on — pick one that has room, e.g. "bottom" near the top of the viewport. */
21
+ tooltipPosition?: TooltipPosition;
16
22
  children?: Snippet;
17
23
  class?: string;
18
24
  }
@@ -23,6 +29,8 @@
23
29
  dot = false,
24
30
  loading = false,
25
31
  outline = false,
32
+ tooltip,
33
+ tooltipPosition = "top",
26
34
  children,
27
35
  class: className = "",
28
36
  }: Props = $props();
@@ -91,37 +99,47 @@
91
99
  };
92
100
  </script>
93
101
 
94
- <span
95
- class="{baseClasses} {outline
96
- ? variantClasses[variant].outline
97
- : variantClasses[variant].solid} {sizeClasses[size]} {className}"
98
- >
99
- {#if dot}
100
- {#if loading}
101
- <svg
102
- class="{spinnerSizeClasses[size]} animate-spin {indicatorTextColors[variant]}"
103
- viewBox="0 0 24 24"
104
- fill="none"
105
- >
106
- <circle
107
- class="opacity-25"
108
- cx="12"
109
- cy="12"
110
- r="10"
111
- stroke="currentColor"
112
- stroke-width="4"
113
- ></circle>
114
- <path
115
- class="opacity-75"
116
- fill="currentColor"
117
- d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
118
- ></path>
119
- </svg>
120
- {:else}
121
- <span class="h-1.5 w-1.5 rounded-full {dotColors[variant]}"></span>
102
+ {#snippet chip(extraClass: string)}
103
+ <span
104
+ class="{baseClasses} {outline
105
+ ? variantClasses[variant].outline
106
+ : variantClasses[variant].solid} {sizeClasses[size]} {extraClass}"
107
+ >
108
+ {#if dot}
109
+ {#if loading}
110
+ <svg
111
+ class="{spinnerSizeClasses[size]} animate-spin {indicatorTextColors[variant]}"
112
+ viewBox="0 0 24 24"
113
+ fill="none"
114
+ >
115
+ <circle
116
+ class="opacity-25"
117
+ cx="12"
118
+ cy="12"
119
+ r="10"
120
+ stroke="currentColor"
121
+ stroke-width="4"
122
+ ></circle>
123
+ <path
124
+ class="opacity-75"
125
+ fill="currentColor"
126
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
127
+ ></path>
128
+ </svg>
129
+ {:else}
130
+ <span class="h-1.5 w-1.5 rounded-full {dotColors[variant]}"></span>
131
+ {/if}
122
132
  {/if}
123
- {/if}
124
- {#if children}
125
- {@render children()}
126
- {/if}
127
- </span>
133
+ {#if children}
134
+ {@render children()}
135
+ {/if}
136
+ </span>
137
+ {/snippet}
138
+
139
+ {#if tooltip}
140
+ <Tooltip content={tooltip} position={tooltipPosition} class={className} wide>
141
+ {@render chip("")}
142
+ </Tooltip>
143
+ {:else}
144
+ {@render chip(className)}
145
+ {/if}
@@ -38,7 +38,10 @@
38
38
  };
39
39
  </script>
40
40
 
41
- <div class="group relative inline-block {className}">
41
+ <!-- Named group: an unnamed `group` would also fire on any ancestor's own
42
+ `group-hover` (e.g. a hoverable card row this tooltip sits inside),
43
+ popping every tooltip in that row open at once. -->
44
+ <div class="group/tooltip relative inline-block {className}">
42
45
  {@render children()}
43
46
 
44
47
  <!-- Hover intent: 100ms before it appears, so sweeping the pointer across a
@@ -52,7 +55,7 @@
52
55
  text-xs
53
56
  {wide ? 'w-max max-w-xs whitespace-normal' : 'whitespace-nowrap'}
54
57
  text-on-surface opacity-0 transition-[opacity,visibility]
55
- delay-100 duration-0 group-hover:visible group-hover:opacity-100
58
+ delay-100 duration-0 group-hover/tooltip:visible group-hover/tooltip:opacity-100
56
59
  "
57
60
  role="tooltip"
58
61
  >
@@ -274,9 +274,9 @@ describe("triggerDescription", () => {
274
274
  });
275
275
 
276
276
  describe("FILTERABLE_TRIGGERS", () => {
277
- it("offers every trigger except cloud", () => {
277
+ it("offers every trigger except station", () => {
278
278
  expect(FILTERABLE_TRIGGERS).toEqual(["cron", "api", "ui", "cli", "service", "startup"]);
279
- expect(FILTERABLE_TRIGGERS).not.toContain("cloud");
279
+ expect(FILTERABLE_TRIGGERS).not.toContain("station");
280
280
  });
281
281
  });
282
282
 
@@ -225,7 +225,7 @@ export function humanizeStatus(status: string): string {
225
225
 
226
226
  /**
227
227
  * Descriptive label for a run's trigger source — fuller than the one-word row
228
- * badge (`formatTriggeredByLabel`) for the "cron"/"cloud"/"service"/"startup"
228
+ * badge (`formatTriggeredByLabel`) for the "cron"/"station"/"service"/"startup"
229
229
  * sources, where the extra words disambiguate (e.g. "REST API" vs a bare
230
230
  * "API"). "ui" and "cli" already read fine as their bare badge word, so those
231
231
  * two match `formatTriggeredByLabel` exactly.
@@ -243,7 +243,7 @@ export function triggerDescription(trigger: string): string {
243
243
  return "UI";
244
244
  case "cli":
245
245
  return "CLI";
246
- case "cloud":
246
+ case "station":
247
247
  return "Control plane";
248
248
  case "service":
249
249
  return "Service auto-start";
@@ -255,11 +255,11 @@ export function triggerDescription(trigger: string): string {
255
255
  }
256
256
 
257
257
  /**
258
- * The triggers offered in the filter dropdown. `cloud` is intentionally
259
- * excluded for now — control-plane runs still carry the `cloud` trigger, but
258
+ * The triggers offered in the filter dropdown. `station` is intentionally
259
+ * excluded for now — control-plane runs still carry the `station` trigger, but
260
260
  * it isn't a selectable filter dimension.
261
261
  */
262
- export const FILTERABLE_TRIGGERS: readonly Trigger[] = TRIGGERS.filter((t) => t !== "cloud");
262
+ export const FILTERABLE_TRIGGERS: readonly Trigger[] = TRIGGERS.filter((t) => t !== "station");
263
263
 
264
264
  /** Chip label for the status dimension — names a whole bucket when it matches. */
265
265
  export function statusChipLabel(statuses: string[]): string {
@@ -112,7 +112,7 @@ describe("formatTriggeredByLabel", () => {
112
112
  expect(formatTriggeredByLabel("cron")).toBe("Cron");
113
113
  expect(formatTriggeredByLabel("service")).toBe("Service");
114
114
  expect(formatTriggeredByLabel("startup")).toBe("Startup");
115
- expect(formatTriggeredByLabel("cloud")).toBe("Cloud");
115
+ expect(formatTriggeredByLabel("station")).toBe("Station");
116
116
  });
117
117
  });
118
118
 
@@ -90,7 +90,7 @@ export function formatTriggeredByLabel(triggeredBy: Run["triggeredBy"]): string
90
90
  if (triggeredBy === "cron") return "Cron";
91
91
  if (triggeredBy === "service") return "Service";
92
92
  if (triggeredBy === "startup") return "Startup";
93
- return "Cloud";
93
+ return "Station";
94
94
  }
95
95
 
96
96
  /**