@boyernick/standard-ui-react 0.2.1-canary.35 → 0.2.1-canary.36

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@boyernick/standard-ui-react",
3
- "version": "0.2.1-canary.35",
3
+ "version": "0.2.1-canary.36",
4
4
  "description": "React components for StandardUI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -641,6 +641,7 @@ export const BlockEditor = ({
641
641
  handle: HTMLElement
642
642
  } | null>(null)
643
643
  const editorRef = useRef<HTMLDivElement>(null)
644
+ const slashPopupRef = useRef<HTMLDivElement>(null)
644
645
  const listRef = useRef<HTMLDivElement>(null)
645
646
 
646
647
  const setBlocks = useCallback(
@@ -1051,17 +1052,16 @@ export const BlockEditor = ({
1051
1052
 
1052
1053
  const openCommands = slash ? filterCommands(slash.query) : []
1053
1054
 
1055
+ // The menu tracks a slash query the caret is sitting in, so any pointer down
1056
+ // that moves the caret elsewhere has to take the menu with it — a different
1057
+ // block, the blank canvas below the last one, or the page around the editor.
1058
+ // Only the menu's own surface is exempt: closing on `mousedown` inside it
1059
+ // would unmount the item before its click ever lands.
1054
1060
  useEffect(() => {
1055
1061
  if (!slash) return
1056
1062
  const handlePointer = (event: MouseEvent) => {
1057
1063
  if (!(event.target instanceof Node)) return
1058
- if (editorRef.current?.contains(event.target)) return
1059
- if (
1060
- event.target instanceof Element &&
1061
- event.target.closest("[data-slot=menu-popup], [role=menu]")
1062
- ) {
1063
- return
1064
- }
1064
+ if (slashPopupRef.current?.contains(event.target)) return
1065
1065
  setSlash(null)
1066
1066
  }
1067
1067
  document.addEventListener("mousedown", handlePointer)
@@ -1699,6 +1699,7 @@ export const BlockEditor = ({
1699
1699
 
1700
1700
  {slash ? (
1701
1701
  <div
1702
+ ref={slashPopupRef}
1702
1703
  role="listbox"
1703
1704
  aria-label="Insert block"
1704
1705
  style={{ top: slash.top + 8, left: slash.left }}
@@ -344,7 +344,14 @@ export const VideoPlayer = ({
344
344
  {!failed && !loading ? (
345
345
  <div
346
346
  className={cn(
347
- "absolute inset-x-0 bottom-0 flex translate-y-0 flex-col bg-gradient-to-t from-black/80 via-black/40 to-transparent px-2.5 pt-14 pb-2.5 transition-[opacity,transform] duration-[var(--duration-md)] ease-enter group-data-[fullscreen]:px-5 group-data-[fullscreen]:pb-5 motion-reduce:transition-none",
347
+ // The scrim samples 0.8 0 along smootherstep
348
+ // (`6t⁵ − 15t⁴ + 10t³`) rather than using a three-stop gradient.
349
+ // Three stops are a run of straight segments, and the eye reads
350
+ // every slope change between them as a seam; flat or evenly lit
351
+ // footage shows those plainly. This curve is flat at both ends
352
+ // instead — no edge where the scrim starts, no corner where it
353
+ // reaches full strength behind the controls.
354
+ "absolute inset-x-0 bottom-0 flex translate-y-0 flex-col bg-[linear-gradient(to_top,rgba(0,0,0,0.8)_0%,rgba(0,0,0,0.79)_12.5%,rgba(0,0,0,0.72)_25%,rgba(0,0,0,0.58)_37.5%,rgba(0,0,0,0.4)_50%,rgba(0,0,0,0.22)_62.5%,rgba(0,0,0,0.08)_75%,rgba(0,0,0,0.01)_87.5%,transparent_100%)] px-2.5 pt-14 pb-2.5 transition-[opacity,transform] duration-[var(--duration-md)] ease-enter group-data-[fullscreen]:px-5 group-data-[fullscreen]:pb-5 motion-reduce:transition-none",
348
355
  "group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100",
349
356
  // Nothing hovers on a touch screen, so the chrome would never come
350
357
  // back once playback started. Keep it visible there instead.