goey-toast 0.4.1 → 0.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.
- package/README.md +18 -0
- package/bin/cli.mjs +110 -0
- package/package.json +7 -2
- package/skills/goey-toast/SKILL.md +152 -0
package/README.md
CHANGED
|
@@ -44,6 +44,24 @@ npx shadcn@latest add https://goey-toast.vercel.app/r/goey-toaster.json
|
|
|
44
44
|
|
|
45
45
|
This installs a thin wrapper component at `components/ui/goey-toaster.tsx` and auto-installs the `goey-toast` and `framer-motion` packages.
|
|
46
46
|
|
|
47
|
+
### AI Agents (Skill)
|
|
48
|
+
|
|
49
|
+
goey-toast ships a bundled [Agent Skill](https://www.skills.sh/) (`SKILL.md`) so coding agents (Claude Code, Cursor, etc.) know how to install and use it correctly — the required `<GooeyToaster />` mount, the `styles.css` import, and the full API.
|
|
50
|
+
|
|
51
|
+
Install from the skills.sh registry:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npx skills add anl331/goey-toast
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Or copy the skill into your project from the package itself:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx goey-toast add-skill # -> .claude/skills/goey-toast/SKILL.md
|
|
61
|
+
npx goey-toast add-skill --agents # also append an AGENTS.md pointer
|
|
62
|
+
npx goey-toast add-skill --dir .cursor/skills/goey-toast
|
|
63
|
+
```
|
|
64
|
+
|
|
47
65
|
### Peer Dependencies
|
|
48
66
|
|
|
49
67
|
goey-toast requires the following peer dependencies:
|
package/bin/cli.mjs
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// goey-toast CLI — install the agent skill into a project so coding agents
|
|
3
|
+
// (Claude Code, Cursor, etc.) know how to install and use goey-toast.
|
|
4
|
+
//
|
|
5
|
+
// Usage:
|
|
6
|
+
// npx goey-toast add-skill # -> ./.claude/skills/goey-toast/SKILL.md
|
|
7
|
+
// npx goey-toast add-skill --agents # also write ./AGENTS.md pointer
|
|
8
|
+
// npx goey-toast add-skill --dir .codex/skills
|
|
9
|
+
// npx goey-toast print-skill # print SKILL.md to stdout
|
|
10
|
+
|
|
11
|
+
import { fileURLToPath } from 'node:url'
|
|
12
|
+
import { dirname, join, resolve } from 'node:path'
|
|
13
|
+
import {
|
|
14
|
+
mkdirSync,
|
|
15
|
+
copyFileSync,
|
|
16
|
+
readFileSync,
|
|
17
|
+
writeFileSync,
|
|
18
|
+
existsSync,
|
|
19
|
+
} from 'node:fs'
|
|
20
|
+
|
|
21
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
22
|
+
const SKILL_SRC = resolve(__dirname, '..', 'skills', 'goey-toast', 'SKILL.md')
|
|
23
|
+
|
|
24
|
+
const argv = process.argv.slice(2)
|
|
25
|
+
const cmd = argv[0]
|
|
26
|
+
|
|
27
|
+
function getFlag(name) {
|
|
28
|
+
const i = argv.indexOf(`--${name}`)
|
|
29
|
+
if (i === -1) return undefined
|
|
30
|
+
const next = argv[i + 1]
|
|
31
|
+
return next && !next.startsWith('--') ? next : true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function readSkill() {
|
|
35
|
+
if (!existsSync(SKILL_SRC)) {
|
|
36
|
+
console.error(`goey-toast: skill source not found at ${SKILL_SRC}`)
|
|
37
|
+
process.exit(1)
|
|
38
|
+
}
|
|
39
|
+
return readFileSync(SKILL_SRC, 'utf8')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function addSkill() {
|
|
43
|
+
const dir = typeof getFlag('dir') === 'string'
|
|
44
|
+
? getFlag('dir')
|
|
45
|
+
: '.claude/skills/goey-toast'
|
|
46
|
+
const dest = resolve(process.cwd(), dir)
|
|
47
|
+
mkdirSync(dest, { recursive: true })
|
|
48
|
+
const out = join(dest, 'SKILL.md')
|
|
49
|
+
copyFileSync(SKILL_SRC, out)
|
|
50
|
+
console.log(`✓ goey-toast skill installed: ${out}`)
|
|
51
|
+
|
|
52
|
+
if (getFlag('agents')) {
|
|
53
|
+
const agentsPath = resolve(process.cwd(), 'AGENTS.md')
|
|
54
|
+
const pointer =
|
|
55
|
+
'\n## goey-toast\n\n' +
|
|
56
|
+
`See \`${dir}/SKILL.md\` for how to install and use goey-toast ` +
|
|
57
|
+
'(gooey morphing React toasts). Mount `<GooeyToaster />` once and ' +
|
|
58
|
+
"import `'goey-toast/styles.css'` at the app entry.\n"
|
|
59
|
+
if (existsSync(agentsPath)) {
|
|
60
|
+
const cur = readFileSync(agentsPath, 'utf8')
|
|
61
|
+
if (!cur.includes('## goey-toast')) {
|
|
62
|
+
writeFileSync(agentsPath, cur.trimEnd() + '\n' + pointer)
|
|
63
|
+
console.log(`✓ appended goey-toast pointer to ${agentsPath}`)
|
|
64
|
+
} else {
|
|
65
|
+
console.log('• AGENTS.md already references goey-toast — skipped')
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
writeFileSync(agentsPath, '# AGENTS.md\n' + pointer)
|
|
69
|
+
console.log(`✓ created ${agentsPath}`)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log('\nNext: restart your agent so it picks up the new skill.')
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function help() {
|
|
77
|
+
console.log(`goey-toast CLI
|
|
78
|
+
|
|
79
|
+
Commands:
|
|
80
|
+
add-skill Install the agent skill into ./.claude/skills/goey-toast
|
|
81
|
+
--dir <path> Custom target dir (e.g. .codex/skills, .cursor/skills)
|
|
82
|
+
--agents Also add/append an AGENTS.md pointer
|
|
83
|
+
print-skill Print SKILL.md to stdout
|
|
84
|
+
help Show this help
|
|
85
|
+
|
|
86
|
+
Examples:
|
|
87
|
+
npx goey-toast add-skill
|
|
88
|
+
npx goey-toast add-skill --agents
|
|
89
|
+
npx goey-toast add-skill --dir .cursor/skills/goey-toast
|
|
90
|
+
`)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
switch (cmd) {
|
|
94
|
+
case 'add-skill':
|
|
95
|
+
addSkill()
|
|
96
|
+
break
|
|
97
|
+
case 'print-skill':
|
|
98
|
+
process.stdout.write(readSkill())
|
|
99
|
+
break
|
|
100
|
+
case undefined:
|
|
101
|
+
case 'help':
|
|
102
|
+
case '--help':
|
|
103
|
+
case '-h':
|
|
104
|
+
help()
|
|
105
|
+
break
|
|
106
|
+
default:
|
|
107
|
+
console.error(`goey-toast: unknown command "${cmd}"\n`)
|
|
108
|
+
help()
|
|
109
|
+
process.exit(1)
|
|
110
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "goey-toast",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "A gooey, morphing toast component built on Sonner with Framer Motion animations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -18,8 +18,13 @@
|
|
|
18
18
|
"*.css"
|
|
19
19
|
],
|
|
20
20
|
"files": [
|
|
21
|
-
"dist"
|
|
21
|
+
"dist",
|
|
22
|
+
"skills",
|
|
23
|
+
"bin"
|
|
22
24
|
],
|
|
25
|
+
"bin": {
|
|
26
|
+
"goey-toast": "bin/cli.mjs"
|
|
27
|
+
},
|
|
23
28
|
"scripts": {
|
|
24
29
|
"build": "tsup",
|
|
25
30
|
"dev": "tsup --watch",
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: goey-toast
|
|
3
|
+
description: Install and use goey-toast — a gooey, morphing React toast component built on Sonner with Framer Motion. Use when adding toast/notification UI to a React app (success/error/warning/info/promise toasts), or when the user mentions goey-toast / gooey toast.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# goey-toast
|
|
8
|
+
|
|
9
|
+
A gooey, morphing React toast component built on Sonner with Framer Motion
|
|
10
|
+
animations (pill → blob → pill). Use this skill to install the package and write
|
|
11
|
+
correct usage code in any React project.
|
|
12
|
+
|
|
13
|
+
## When to use
|
|
14
|
+
|
|
15
|
+
- Adding toast / notification UI to a React app (React >= 18).
|
|
16
|
+
- The user mentions "goey-toast", "gooey toast", or wants animated/morphing toasts.
|
|
17
|
+
- Replacing raw `sonner` toasts with the gooey variant.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install goey-toast react react-dom framer-motion
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Peer deps (must exist in the host app):
|
|
26
|
+
|
|
27
|
+
| Package | Version |
|
|
28
|
+
| ------------- | --------- |
|
|
29
|
+
| react | >= 18.0.0 |
|
|
30
|
+
| react-dom | >= 18.0.0 |
|
|
31
|
+
| framer-motion | >= 10.0.0 |
|
|
32
|
+
|
|
33
|
+
### shadcn/ui projects
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx shadcn@latest add https://goey-toast.vercel.app/r/goey-toaster.json
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Installs a wrapper at `components/ui/goey-toaster.tsx` and auto-installs deps.
|
|
40
|
+
|
|
41
|
+
## Two required steps to render toasts
|
|
42
|
+
|
|
43
|
+
1. **Mount `<GooeyToaster />` once** near the app root.
|
|
44
|
+
2. **Import the stylesheet once** at the entry point. Without it toasts render
|
|
45
|
+
unstyled.
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { GooeyToaster, gooeyToast } from 'goey-toast'
|
|
49
|
+
import 'goey-toast/styles.css' // REQUIRED — import once at app entry
|
|
50
|
+
|
|
51
|
+
function App() {
|
|
52
|
+
return (
|
|
53
|
+
<>
|
|
54
|
+
<GooeyToaster position="bottom-right" />
|
|
55
|
+
<button onClick={() => gooeyToast.success('Saved!')}>Save</button>
|
|
56
|
+
</>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## API: `gooeyToast`
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
gooeyToast(title, options?) // default (neutral)
|
|
65
|
+
gooeyToast.success(title, options?) // green
|
|
66
|
+
gooeyToast.error(title, options?) // red
|
|
67
|
+
gooeyToast.warning(title, options?) // yellow
|
|
68
|
+
gooeyToast.info(title, options?) // blue
|
|
69
|
+
gooeyToast.promise(promise, data) // loading → success/error
|
|
70
|
+
gooeyToast.update(id, options) // update an existing toast in-place
|
|
71
|
+
gooeyToast.dismiss(idOrFilter?) // dismiss one, by type, or all
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Common options (2nd arg)
|
|
75
|
+
|
|
76
|
+
| Option | Type | Notes |
|
|
77
|
+
| --------------- | ------------------- | ---------------------------------------------- |
|
|
78
|
+
| `description` | `ReactNode` | String or component body |
|
|
79
|
+
| `action` | `GooeyToastAction` | `{ label, onClick, successLabel? }` |
|
|
80
|
+
| `icon` | `ReactNode` | Custom icon (`null` clears in `update`) |
|
|
81
|
+
| `duration` | `number` | ms |
|
|
82
|
+
| `id` | `string \| number` | Stable id (needed for `update`) |
|
|
83
|
+
| `fillColor` / `borderColor` / `borderWidth` | colors / px | Blob styling |
|
|
84
|
+
| `spring` / `bounce` | `boolean` / `number` | bounce `0.05`–`0.8`, default `0.4` |
|
|
85
|
+
| `preset` | `'smooth' \| 'bouncy' \| 'subtle' \| 'snappy'` | Animation preset |
|
|
86
|
+
| `showProgress` | `boolean` | Countdown bar |
|
|
87
|
+
| `showTimestamp` | `boolean` | Default `true` |
|
|
88
|
+
| `onDismiss` / `onAutoClose` | `(id) => void` | Dismiss callbacks |
|
|
89
|
+
|
|
90
|
+
### `<GooeyToaster />` key props
|
|
91
|
+
|
|
92
|
+
`position` (`'top-left'|'top-center'|'top-right'|'bottom-left'|'bottom-center'|'bottom-right'`, default `'bottom-right'`),
|
|
93
|
+
`theme` (`'light'|'dark'`), `closeButton`, `showProgress`, `closeOnEscape`,
|
|
94
|
+
`maxQueue`, `queueOverflow` (`'drop-oldest'|'drop-newest'`), `dir` (`'ltr'|'rtl'`),
|
|
95
|
+
`spring`, `bounce`, `preset`, `swipeToDismiss`, `showTimestamp`, `gap`, `offset`.
|
|
96
|
+
|
|
97
|
+
## Recipes
|
|
98
|
+
|
|
99
|
+
### Description + action button
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
gooeyToast.info('Share link ready', {
|
|
103
|
+
description: 'Your link has been generated.',
|
|
104
|
+
action: {
|
|
105
|
+
label: 'Copy',
|
|
106
|
+
onClick: () => navigator.clipboard.writeText(url),
|
|
107
|
+
successLabel: 'Copied!', // morphs back to pill after click
|
|
108
|
+
},
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Promise toast
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
gooeyToast.promise(saveData(), {
|
|
116
|
+
loading: 'Saving...',
|
|
117
|
+
success: (data) => `Saved ${data.count} items`,
|
|
118
|
+
error: (e) => `Failed: ${String(e)}`,
|
|
119
|
+
description: { success: 'All changes synced.', error: 'Try again later.' },
|
|
120
|
+
action: { error: { label: 'Retry', onClick: () => retry() } },
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Update in place
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
const id = gooeyToast('Uploading...', { icon: <Spinner /> })
|
|
128
|
+
gooeyToast.update(id, { title: 'Done', type: 'success', icon: null })
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Dismiss by filter
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
gooeyToast.dismiss(id) // one
|
|
135
|
+
gooeyToast.dismiss({ type: 'error' }) // all errors
|
|
136
|
+
gooeyToast.dismiss({ type: ['error','warning'] })
|
|
137
|
+
gooeyToast.dismiss() // all
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Gotchas
|
|
141
|
+
|
|
142
|
+
- Forgetting `import 'goey-toast/styles.css'` → unstyled toasts. Most common bug.
|
|
143
|
+
- `<GooeyToaster />` must be mounted exactly once, near the root.
|
|
144
|
+
- `update()` requires the same `id` returned from the create call.
|
|
145
|
+
- `framer-motion` is a peer dep — install it explicitly.
|
|
146
|
+
- Backward-compat aliases exist (`GoeyToaster`, `goeyToast`) for v0.2.x; prefer
|
|
147
|
+
the double-`o` names (`GooeyToaster`, `gooeyToast`).
|
|
148
|
+
|
|
149
|
+
## Reference
|
|
150
|
+
|
|
151
|
+
- Live demo & docs: https://goey-toast.vercel.app
|
|
152
|
+
- npm: https://www.npmjs.com/package/goey-toast
|