libraries-dev-svelte 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -50,7 +50,56 @@ You can also pass CSS `box-shadow` layers directly. Layer order is horizontal of
50
50
  />
51
51
  ```
52
52
 
53
- Props: `blur` (6), `contrast` (18), `fill` (`var(--modal-bg, #fff)`), `shadow` (empty), `onAction` (optional callback for `'new-file'`, `'add-image'`, or `'new-folder'`), `pro` (false), and `bare` (false). `bare` renders only the menu stage and is the recommended mode when embedding it in an application; without it, the tuning panel is included. Selecting a satellite calls `onAction` when supplied and closes the menu. The host can set `--modal-bg`, `--btn-text`, `--stage-bg`, `--accent`, and `--hover-veil` to match its theme.
53
+ Props: `blur` (6), `contrast` (18), `fill` (`var(--modal-bg, #fff)`), `shadow` (empty), `items` (optional custom satellite items), `onAction` (optional callback; receives the selected item's `action` string), `pro` (false), and `bare` (false). `bare` renders only the menu stage and is the recommended mode when embedding it in an application; without it, the tuning panel is included. Selecting a satellite calls `onAction` when supplied and closes the menu. The host can set `--modal-bg`, `--btn-text`, `--stage-bg`, `--accent`, and `--hover-veil` to match its theme.
54
+
55
+ ### Custom items
56
+
57
+ **Note for package users:** `GooeyRadialMenu` no longer ships fixed demo items. By default it still renders the original `New file` / `Add image` / `New folder` demo, but you can pass your own via the `items` prop. Each item is `{ label, action, x, y, iconSnippet? }`, where `x`/`y` are pixel offsets from the main button (positive `y` is down) and `action` is any string reported back through `onAction`. Keep offsets within the stage (the default stage is 200×140 with the main button centered) so satellites stay inside the goo filter. Icons are snippets, so any markup works — including an icon library. If `iconSnippet` is omitted, the built-in `icon` key (`'file' | 'image' | 'folder'`) is used; when neither is set, the item renders unlabeled.
58
+
59
+ ```svelte
60
+ <script lang="ts">
61
+ import { GooeyRadialMenu } from 'libraries-dev-svelte';
62
+
63
+ const items = [
64
+ { label: 'Reply', action: 'reply', x: -54, y: -34 },
65
+ { label: 'Share', action: 'share', x: 0, y: -64 },
66
+ { label: 'Delete', action: 'delete', x: 54, y: -34 },
67
+ ];
68
+
69
+ function handleAction(action: string) {
70
+ if (action === 'delete') confirmDelete();
71
+ }
72
+ </script>
73
+
74
+ <GooeyRadialMenu bare {items} onAction={handleAction} />
75
+ ```
76
+
77
+ With custom icons:
78
+
79
+ ```svelte
80
+ <script lang="ts">
81
+ import { GooeyRadialMenu } from 'libraries-dev-svelte';
82
+ import { Camera, Send, Trash } from 'reicon-svelte';
83
+
84
+ const items = [
85
+ { label: 'Camera', action: 'camera', x: -54, y: -34 },
86
+ { label: 'Send', action: 'send', x: 0, y: -64 },
87
+ { label: 'Delete', action: 'delete', x: 54, y: -34 },
88
+ ];
89
+ </script>
90
+
91
+ <GooeyRadialMenu
92
+ bare
93
+ {items}
94
+ onAction={(action) => console.log(action)}
95
+ >
96
+ {#snippet iconSnippet(item)}
97
+ {#if item.action === 'camera'}<Camera size={16} weight="Outline" />{/if}
98
+ {#if item.action === 'send'}<Send size={16} weight="Outline" />{/if}
99
+ {#if item.action === 'delete'}<Trash size={16} weight="Outline" />{/if}
100
+ {/snippet}
101
+ </GooeyRadialMenu>
102
+ ```
54
103
 
55
104
  ## Demo routes
56
105
 
@@ -1,25 +1,28 @@
1
1
  <script lang="ts">
2
2
  import { onDestroy, onMount } from 'svelte';
3
3
  import { parseShadow, type ShadowLayer } from './shadow';
4
- import type { GooeyMenuAction, GooeyMenuSettings, GooeyRadialMenuProps } from './types';
4
+ import type { GooeyMenuAction, GooeyMenuItem, GooeyMenuSettings, GooeyRadialMenuProps } from './types';
5
5
 
6
6
  let {
7
7
  blur = 6,
8
8
  contrast = 18,
9
9
  fill = 'var(--modal-bg, #fff)',
10
10
  shadow = '',
11
+ items,
11
12
  onAction,
13
+ iconSnippet,
12
14
  pro = false,
13
15
  bare = false,
14
16
  }: GooeyRadialMenuProps & { fill?: string } = $props();
15
17
 
16
18
  const instanceId = $props.id();
17
19
  const filterId = `gooey-${instanceId.replace(/[^a-zA-Z0-9_-]/g, '')}`;
18
- const satellites = [
20
+ const demoItems: GooeyMenuItem[] = [
19
21
  { label: 'New file', action: 'new-file', x: -54, y: -34, icon: 'file' },
20
22
  { label: 'Add image', action: 'add-image', x: 0, y: -64, icon: 'image' },
21
23
  { label: 'New folder', action: 'new-folder', x: 54, y: -34, icon: 'folder' },
22
- ] as const;
24
+ ];
25
+ const satellites = $derived(items ?? demoItems);
23
26
  const defaults: GooeyMenuSettings = {
24
27
  openDur: 550,
25
28
  openEase: 'Bouncy',
@@ -41,8 +44,7 @@
41
44
  Linear: 'linear',
42
45
  };
43
46
  const easeNames = Object.keys(eases);
44
- const allItems = [...satellites, { label: 'Menu', x: 0, y: 0, icon: 'main' as const }];
45
- const initialBoxes: Array<BlobBox | null> = allItems.map(() => null);
47
+ const allItems = $derived([...satellites, { label: 'Menu', x: 0, y: 0, icon: 'main' as const }]);
46
48
 
47
49
  interface BlobBox {
48
50
  x: number;
@@ -62,7 +64,7 @@
62
64
  let itemWrappers: Array<HTMLDivElement | undefined> = [];
63
65
  let satelliteButtons: Array<HTMLButtonElement | undefined> = [];
64
66
  let mainButton: HTMLButtonElement;
65
- let itemBoxes = $state<Array<BlobBox | null>>(initialBoxes);
67
+ let itemBoxes = $state<Array<BlobBox | null>>([]);
66
68
  let groupSize = $state({ w: 0, h: 0 });
67
69
 
68
70
  const shadows = $derived(parseShadow(shadow));
@@ -423,7 +425,9 @@
423
425
  ? `${menuSettings.iconDelay + index * phase.stagger}ms`
424
426
  : '0ms'}
425
427
  >
426
- {#if satellite.icon === 'file'}
428
+ {#if iconSnippet}
429
+ {@render iconSnippet(satellite)}
430
+ {:else if satellite.icon === 'file'}
427
431
  <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round">
428
432
  <path d="M9 1.5H4A1.5 1.5 0 0 0 2.5 3v10A1.5 1.5 0 0 0 4 14.5h8a1.5 1.5 0 0 0 1.5-1.5V6z" />
429
433
  <path d="M9 1.5V6h4.5" />
@@ -1,4 +1,4 @@
1
- /** Inputs accepted by the Goey radial-menu playground component. */
1
+ /** Inputs accepted by the Gooey radial-menu component. */
2
2
  export interface GooeyRadialMenuProps {
3
3
  /** Goo filter blur sigma in px. */
4
4
  blur?: number;
@@ -6,8 +6,12 @@ export interface GooeyRadialMenuProps {
6
6
  contrast?: number;
7
7
  /** CSS box-shadow layers drawn on the merged liquid silhouette. */
8
8
  shadow?: string;
9
- /** Called when a sample action is selected. The menu closes after activation. */
9
+ /** Custom satellite items. Defaults to the original demo items. */
10
+ items?: GooeyMenuItem[];
11
+ /** Called when an item is selected. The menu closes after activation. */
10
12
  onAction?: (action: GooeyMenuAction) => void;
13
+ /** Snippet rendering each item's icon; receives the item. Falls back to the built-in demo icons. */
14
+ iconSnippet?: Snippet<[GooeyMenuItem]>;
11
15
  /** Surface color for the merged liquid. Defaults to the host theme's modal color. */
12
16
  fill?: string;
13
17
  /** Show all raw tuning controls, export, and reset controls. */
@@ -15,7 +19,20 @@ export interface GooeyRadialMenuProps {
15
19
  /** Render only the menu stage for embedding in a host layout. */
16
20
  bare?: boolean;
17
21
  }
18
- export type GooeyMenuAction = 'new-file' | 'add-image' | 'new-folder';
22
+ /** A satellite item rendered around the main button. */
23
+ import type { Snippet } from 'svelte';
24
+ export interface GooeyMenuItem {
25
+ /** Accessible label (also the `aria-label`). */
26
+ label: string;
27
+ /** Stable identifier reported to `onAction`. */
28
+ action: string;
29
+ /** Offset in px from the main button (positive y is down). */
30
+ x: number;
31
+ y: number;
32
+ /** Built-in demo icon key: 'file' | 'image' | 'folder'. Used when the component's `iconSnippet` prop is not set. */
33
+ icon?: 'file' | 'image' | 'folder';
34
+ }
35
+ export type GooeyMenuAction = string;
19
36
  export interface GooeyMenuSettings {
20
37
  openDur: number;
21
38
  openEase: string;
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export { default as BotAvatar } from './bot-avatars/BotAvatar.svelte';
2
2
  export { default } from './bot-avatars/BotAvatar.svelte';
3
3
  export { default as GooeyRadialMenu } from './gooey-radial-menu/GooeyRadialMenu.svelte';
4
4
  export { gooeyShadowPresets } from './gooey-radial-menu/shadow';
5
- export type { GooeyMenuAction, GooeyMenuSettings, GooeyRadialMenuProps } from './gooey-radial-menu/types';
5
+ export type { GooeyMenuAction, GooeyMenuItem, GooeyMenuSettings, GooeyRadialMenuProps } from './gooey-radial-menu/types';
6
6
  export { botAvatarPresets, botAvatarPalette, botAvatarTypes, botAvatarFaces, botAvatarStates, } from './bot-avatars/presets';
7
7
  export { SHAPE_PATHS as botAvatarShapes, SHAPE_PARTS as botAvatarParts } from './bot-avatars/shapes';
8
8
  export { autoInk, luminance, parseColor, shade } from './bot-avatars/color';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libraries-dev-svelte",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Svelte ports of Bot Avatars and the Gooey radial menu from Libraries.dev",
5
5
  "license": "MIT",
6
6
  "scripts": {