@dfosco/storyboard-react 4.0.0-beta.6 → 4.0.0-beta.8

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,10 +1,10 @@
1
1
  {
2
2
  "name": "@dfosco/storyboard-react",
3
- "version": "4.0.0-beta.6",
3
+ "version": "4.0.0-beta.8",
4
4
  "type": "module",
5
5
  "dependencies": {
6
- "@dfosco/storyboard-core": "4.0.0-beta.6",
7
- "@dfosco/tiny-canvas": "4.0.0-beta.6",
6
+ "@dfosco/storyboard-core": "4.0.0-beta.8",
7
+ "@dfosco/tiny-canvas": "4.0.0-beta.8",
8
8
  "@neodrag/react": "^2.3.1",
9
9
  "glob": "^11.0.0",
10
10
  "jsonc-parser": "^3.3.1",
@@ -47,6 +47,35 @@ function resolveCanvasThemeFromStorage() {
47
47
  return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
48
48
  }
49
49
 
50
+ /**
51
+ * Get the copyable URL for a widget based on its type.
52
+ * Returns the most relevant URL/path for the widget content.
53
+ */
54
+ function getWidgetCopyableUrl(widget) {
55
+ const { type, props = {} } = widget
56
+ const base = (typeof import.meta !== 'undefined' && import.meta.env?.BASE_URL) || '/'
57
+ switch (type) {
58
+ case 'prototype':
59
+ // Prototype src is a path like "/MyPrototype" - make it a full URL
60
+ return props.src ? `${window.location.origin}${base.replace(/\/$/, '')}${props.src}` : ''
61
+ case 'figma-embed':
62
+ return props.url || ''
63
+ case 'link-preview':
64
+ return props.url || ''
65
+ case 'image':
66
+ // Return the served image URL
67
+ return props.src ? `${window.location.origin}${base.replace(/\/$/, '')}/_storyboard/canvas/images/${props.src}` : ''
68
+ case 'sticky-note':
69
+ // Sticky notes have text content, not a URL
70
+ return props.text || ''
71
+ case 'markdown':
72
+ // Markdown has content, not a URL
73
+ return props.content || ''
74
+ default:
75
+ return ''
76
+ }
77
+ }
78
+
50
79
  /**
51
80
  * Debounce helper — returns a function that delays invocation.
52
81
  * Exposes `.cancel()` to abort pending calls (used by undo/redo).
@@ -977,6 +1006,34 @@ export default function CanvasPage({ name }) {
977
1006
  e.preventDefault()
978
1007
  setSelectedWidgetIds(new Set())
979
1008
  }
1009
+ // Copy shortcuts (single widget selected):
1010
+ // - cmd+c → copy URL/content
1011
+ // - Shift+C (no cmd) → copy widget ID (or file path for images)
1012
+ const mod = e.metaKey || e.ctrlKey
1013
+ if (mod && e.key === 'c' && !e.shiftKey && selectedWidgetIds.size === 1) {
1014
+ const widgetId = [...selectedWidgetIds][0]
1015
+ const widget = localWidgets?.find(w => w.id === widgetId)
1016
+ if (widget) {
1017
+ e.preventDefault()
1018
+ const url = getWidgetCopyableUrl(widget)
1019
+ if (url) {
1020
+ navigator.clipboard.writeText(url).catch(() => {})
1021
+ }
1022
+ }
1023
+ }
1024
+ // Shift+C (uppercase C, no cmd) → copy ID or file path
1025
+ if (e.key === 'C' && e.shiftKey && !mod && selectedWidgetIds.size === 1) {
1026
+ const widgetId = [...selectedWidgetIds][0]
1027
+ const widget = localWidgets?.find(w => w.id === widgetId)
1028
+ if (widget) {
1029
+ e.preventDefault()
1030
+ if (widget.type === 'image' && widget.props?.src) {
1031
+ navigator.clipboard.writeText(`src/canvas/images/${widget.props.src}`).catch(() => {})
1032
+ } else {
1033
+ navigator.clipboard.writeText(widgetId).catch(() => {})
1034
+ }
1035
+ }
1036
+ }
980
1037
  if (e.key === 'Delete' || e.key === 'Backspace') {
981
1038
  e.preventDefault()
982
1039
  if (selectedWidgetIds.size > 1) {
@@ -1002,7 +1059,7 @@ export default function CanvasPage({ name }) {
1002
1059
  }
1003
1060
  document.addEventListener('keydown', handleKeyDown)
1004
1061
  return () => document.removeEventListener('keydown', handleKeyDown)
1005
- }, [selectedWidgetIds, handleWidgetRemove, undoRedo, name, debouncedSave])
1062
+ }, [selectedWidgetIds, localWidgets, handleWidgetRemove, undoRedo, name, debouncedSave])
1006
1063
 
1007
1064
  // Paste handler — images become image widgets, same-origin URLs become prototypes,
1008
1065
  // other URLs become link previews, text becomes markdown