goey-toast 0.4.0 → 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 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:
@@ -224,6 +242,7 @@ Props for the `<GooeyToaster />` component.
224
242
  | `queueOverflow` | `'drop-oldest' \| 'drop-newest'` | `'drop-oldest'` | Queue overflow strategy |
225
243
  | `dir` | `'ltr' \| 'rtl'` | `'ltr'` | Layout direction |
226
244
  | `swipeToDismiss` | `boolean` | `true` | Enable swipe-to-dismiss on mobile |
245
+ | `showTimestamp` | `boolean` | `true` | Show/hide timestamp on all toasts globally |
227
246
 
228
247
  ### `GooeyPromiseData<T>`
229
248
 
@@ -439,10 +458,12 @@ The close button inherits the toast's border and fill color styling. Hidden duri
439
458
 
440
459
  ### Hiding Timestamps
441
460
 
442
- Hide the timestamp from toasts:
443
-
444
461
  ```tsx
462
+ // Per-toast: hide timestamp for this toast only
445
463
  gooeyToast.success('Saved', { showTimestamp: false })
464
+
465
+ // Globally: hide timestamp for all toasts
466
+ <GooeyToaster showTimestamp={false} />
446
467
  ```
447
468
 
448
469
  ## Exports
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/dist/index.cjs CHANGED
@@ -86,6 +86,13 @@ function setGooeyShowProgress(show) {
86
86
  function getGooeyShowProgress() {
87
87
  return _showProgress;
88
88
  }
89
+ var _showTimestamp = true;
90
+ function setGooeyShowTimestamp(show) {
91
+ _showTimestamp = show;
92
+ }
93
+ function getGooeyShowTimestamp() {
94
+ return _showTimestamp;
95
+ }
89
96
  var _closeButton = false;
90
97
  function setGooeyCloseButton(value) {
91
98
  _closeButton = value;
@@ -341,23 +348,23 @@ function registerSonnerObserver(ol, callback) {
341
348
  let entry = observerRegistry.get(ol);
342
349
  if (!entry) {
343
350
  const callbacks = /* @__PURE__ */ new Set();
344
- let applying = false;
345
- const observer = new MutationObserver(() => {
346
- if (applying) return;
347
- applying = true;
348
- requestAnimationFrame(() => {
349
- callbacks.forEach((cb) => cb());
350
- requestAnimationFrame(() => {
351
- applying = false;
352
- });
353
- });
354
- });
355
- observer.observe(ol, {
351
+ const observeOptions = {
356
352
  attributes: true,
357
353
  attributeFilter: ["style", "data-visible"],
358
354
  subtree: true,
359
355
  childList: true
356
+ };
357
+ const observer = new MutationObserver(() => {
358
+ observer.disconnect();
359
+ try {
360
+ for (const cb of callbacks) {
361
+ cb();
362
+ }
363
+ } finally {
364
+ observer.observe(ol, observeOptions);
365
+ }
360
366
  });
367
+ observer.observe(ol, observeOptions);
361
368
  entry = { observer, callbacks };
362
369
  observerRegistry.set(ol, entry);
363
370
  }
@@ -385,17 +392,10 @@ function syncSonnerHeights(wrapperEl, includeOffsets = false) {
385
392
  const h = content ? content.getBoundingClientRect().height : 0;
386
393
  return h > 0 ? h : PH;
387
394
  });
388
- const isExpanded = includeOffsets && toasts[0]?.getAttribute("data-expanded") === "true";
389
- if (isExpanded) {
390
- for (const t of toasts) t.style.setProperty("transition", "none", "important");
391
- }
392
395
  for (let i = 0; i < toasts.length; i++) {
393
396
  toasts[i].style.setProperty("--initial-height", `${heights[i]}px`);
394
397
  }
395
398
  if (!includeOffsets) {
396
- if (isExpanded) {
397
- for (const t of toasts) t.style.removeProperty("transition");
398
- }
399
399
  return;
400
400
  }
401
401
  const gapStr = getComputedStyle(ol).getPropertyValue("--gap").trim();
@@ -411,10 +411,6 @@ function syncSonnerHeights(wrapperEl, includeOffsets = false) {
411
411
  runningOffset += heights[i] + gap;
412
412
  }
413
413
  }
414
- if (isExpanded) {
415
- void ol.offsetHeight;
416
- for (const t of toasts) t.style.removeProperty("transition");
417
- }
418
414
  }
419
415
  function memoizePath(fn) {
420
416
  let lastArgs = null;
@@ -545,7 +541,7 @@ var GooeyToast = ({
545
541
  preset,
546
542
  spring: springProp,
547
543
  bounce: bounceProp,
548
- showTimestamp = true,
544
+ showTimestamp: showTimestampProp,
549
545
  showProgress: showProgressProp,
550
546
  toastId
551
547
  }) => {
@@ -563,6 +559,7 @@ var GooeyToast = ({
563
559
  const useSpring = springProp ?? presetConfig?.spring ?? getGooeySpring();
564
560
  const bounceVal = bounceProp ?? presetConfig?.bounce ?? getGooeyBounce() ?? 0.4;
565
561
  const showProgress = showProgressProp ?? getGooeyShowProgress();
562
+ const showTimestamp = showTimestampProp ?? getGooeyShowTimestamp();
566
563
  const [actionSuccess, setActionSuccess] = react.useState(null);
567
564
  const [dismissing, setDismissing] = react.useState(false);
568
565
  const [progressKey, setProgressKey] = react.useState(0);
@@ -1767,7 +1764,8 @@ function GooeyToaster({
1767
1764
  closeOnEscape = true,
1768
1765
  maxQueue = Infinity,
1769
1766
  queueOverflow = "drop-oldest",
1770
- showProgress = false
1767
+ showProgress = false,
1768
+ showTimestamp = true
1771
1769
  }) {
1772
1770
  const presetConfig = preset ? animationPresets[preset] : void 0;
1773
1771
  const resolvedSpring = spring ?? presetConfig?.spring ?? true;
@@ -1820,6 +1818,9 @@ function GooeyToaster({
1820
1818
  react.useEffect(() => {
1821
1819
  setGooeyCloseButton(closeButton ?? false);
1822
1820
  }, [closeButton]);
1821
+ react.useEffect(() => {
1822
+ setGooeyShowTimestamp(showTimestamp);
1823
+ }, [showTimestamp]);
1823
1824
  react.useEffect(() => {
1824
1825
  let expandObs = null;
1825
1826
  let currentOl = null;