@blockprotocol/hook
Advanced tools
Comparing version 0.0.1-canary.3 to 0.0.1-canary.4
@@ -25,3 +25,3 @@ import { RefObject } from "react"; | ||
}; | ||
export declare const useHook: <T extends HTMLElement>(service: HookBlockHandler | null, ref: RefObject<T>, type: string, path: string, fallback: (node: T | null) => void | (() => void)) => void; | ||
export declare const useHook: <T extends HTMLElement>(service: HookBlockHandler | null, ref: RefObject<void | T | null>, type: string, path: string, fallback: (node: T) => void | (() => void)) => void; | ||
export declare const useHookRef: <T extends HTMLElement>(service: HookBlockHandler | null, type: string, path: string, fallback: (node: T | null) => void) => (node: T | null) => void; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -58,82 +67,112 @@ exports.useHookRef = exports.useHook = exports.useHookEmbedderService = exports.useHookBlockService = void 0; | ||
const useHook = (service, ref, type, path, fallback) => { | ||
const hookId = (0, react_1.useRef)(null); | ||
const controllerRef = (0, react_1.useRef)(null); | ||
const fallbackRef = (0, react_1.useRef)(fallback); | ||
const hookRef = (0, react_1.useRef)(null); | ||
const [, setError] = (0, react_1.useState)(); | ||
const lastNode = (0, react_1.useRef)(null); | ||
const teardownRef = (0, react_1.useRef)(null); | ||
const messageQueue = (0, react_1.useRef)(initialMessageQueue); | ||
const fallbackRef = (0, react_1.useRef)(fallback); | ||
(0, react_1.useLayoutEffect)(() => { | ||
fallbackRef.current = fallback; | ||
}); | ||
(0, react_1.useLayoutEffect)(() => { | ||
return () => { | ||
var _a; | ||
(_a = controllerRef.current) === null || _a === void 0 ? void 0 : _a.abort(); | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
messageQueue.current = messageQueue.current | ||
.catch() | ||
.then(() => { var _a, _b; return (_b = (_a = hookRef.current) === null || _a === void 0 ? void 0 : _a.teardown) === null || _b === void 0 ? void 0 : _b.call(_a).then(() => { }); }) | ||
.catch((err) => { | ||
setError(() => { | ||
throw err; | ||
}); | ||
}); | ||
}; | ||
}, []); | ||
(0, react_1.useLayoutEffect)(() => { | ||
var _a; | ||
var _a, _b, _c; | ||
const existingHook = (_a = hookRef.current) === null || _a === void 0 ? void 0 : _a.params; | ||
const node = ref.current; | ||
if (lastNode.current === node) { | ||
return; | ||
if (existingHook) { | ||
if (existingHook.service === service && | ||
existingHook.node === node && | ||
existingHook.path === path && | ||
existingHook.type === type) { | ||
return; | ||
} | ||
} | ||
(_a = controllerRef.current) === null || _a === void 0 ? void 0 : _a.abort(); | ||
const controller = new AbortController(); | ||
controllerRef.current = controller; | ||
lastNode.current = ref.current; | ||
messageQueue.current = messageQueue.current | ||
const teardownPromise = messageQueue.current | ||
.catch() | ||
.then(() => service === null || service === void 0 ? void 0 : service.hook({ | ||
data: { | ||
hookId: hookId.current, | ||
node, | ||
type, | ||
path, | ||
}, | ||
}).then((response) => { | ||
var _a; | ||
if (!controller.signal.aborted) { | ||
if (response.errors) { | ||
if (response.errors.length === 1 && | ||
response.errors[0].code === "NOT_IMPLEMENTED") { | ||
teardownRef.current = (_a = fallbackRef.current(node)) !== null && _a !== void 0 ? _a : null; | ||
} | ||
else { | ||
// eslint-disable-next-line no-console | ||
console.error(response.errors); | ||
throw new Error("Unknown error in hook"); | ||
} | ||
} | ||
else if (response.data) { | ||
hookId.current = response.data.hookId; | ||
teardownRef.current = () => { | ||
messageQueue.current = messageQueue.current | ||
.catch() | ||
.then(() => service === null || service === void 0 ? void 0 : service.hook({ | ||
.then(() => { var _a, _b; return (_b = (_a = hookRef.current) === null || _a === void 0 ? void 0 : _a.teardown) === null || _b === void 0 ? void 0 : _b.call(_a).catch(); }); | ||
if (node && service) { | ||
const controller = new AbortController(); | ||
const reuseId = existingHook && | ||
existingHook.service === service && | ||
existingHook.path === path && | ||
existingHook.type === type; | ||
const hook = { | ||
id: reuseId ? (_c = (_b = hookRef.current) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : null : null, | ||
params: { | ||
service, | ||
type, | ||
path, | ||
node, | ||
}, | ||
teardown: () => __awaiter(void 0, void 0, void 0, function* () { | ||
controller.abort(); | ||
try { | ||
yield service.hook({ | ||
data: { | ||
hookId: hookId.current, | ||
hookId: hook.id, | ||
path, | ||
type, | ||
node: null, | ||
type, | ||
path, | ||
}, | ||
}).then(() => { })) | ||
.catch((err) => { | ||
if (!controller.signal.aborted) { | ||
setError(() => { | ||
throw err; | ||
}); | ||
} | ||
catch (err) { | ||
setError(() => { | ||
throw err; | ||
}); | ||
} | ||
}), | ||
}; | ||
messageQueue.current = teardownPromise.then(() => { | ||
return service | ||
.hook({ | ||
data: { | ||
hookId: hook.id, | ||
node, | ||
type, | ||
path, | ||
}, | ||
}) | ||
.then((response) => { | ||
if (!controller.signal.aborted) { | ||
if (response.errors) { | ||
if (response.errors.length === 1 && | ||
response.errors[0].code === "NOT_IMPLEMENTED") { | ||
const teardown = fallbackRef.current(node); | ||
hook.teardown = () => __awaiter(void 0, void 0, void 0, function* () { | ||
controller.abort(); | ||
yield (teardown === null || teardown === void 0 ? void 0 : teardown()); | ||
}); | ||
} | ||
}); | ||
}; | ||
} | ||
} | ||
})) | ||
.catch((err) => { | ||
setError(() => { | ||
throw err; | ||
else { | ||
// eslint-disable-next-line no-console | ||
console.error(response.errors); | ||
throw new Error("Unknown error in hook"); | ||
} | ||
} | ||
else if (response.data) { | ||
hook.id = response.data.hookId; | ||
} | ||
} | ||
}) | ||
.catch((err) => { | ||
setError(() => { | ||
throw err; | ||
}); | ||
}); | ||
}); | ||
}); | ||
return () => { | ||
var _a; | ||
(_a = teardownRef.current) === null || _a === void 0 ? void 0 : _a.call(teardownRef); | ||
teardownRef.current = null; | ||
}; | ||
} | ||
else { | ||
hookRef.current = null; | ||
} | ||
}); | ||
@@ -140,0 +179,0 @@ }; |
@@ -25,3 +25,3 @@ import { RefObject } from "react"; | ||
}; | ||
export declare const useHook: <T extends HTMLElement>(service: HookBlockHandler | null, ref: RefObject<T>, type: string, path: string, fallback: (node: T | null) => void | (() => void)) => void; | ||
export declare const useHook: <T extends HTMLElement>(service: HookBlockHandler | null, ref: RefObject<void | T | null>, type: string, path: string, fallback: (node: T) => void | (() => void)) => void; | ||
export declare const useHookRef: <T extends HTMLElement>(service: HookBlockHandler | null, type: string, path: string, fallback: (node: T | null) => void) => (node: T | null) => void; |
@@ -0,1 +1,10 @@ | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
import { useCallback, useEffect, useLayoutEffect, useRef, useState, } from "react"; | ||
@@ -53,82 +62,112 @@ import { HookBlockHandler, HookEmbedderHandler } from "./index"; | ||
export const useHook = (service, ref, type, path, fallback) => { | ||
const hookId = useRef(null); | ||
const controllerRef = useRef(null); | ||
const fallbackRef = useRef(fallback); | ||
const hookRef = useRef(null); | ||
const [, setError] = useState(); | ||
const lastNode = useRef(null); | ||
const teardownRef = useRef(null); | ||
const messageQueue = useRef(initialMessageQueue); | ||
const fallbackRef = useRef(fallback); | ||
useLayoutEffect(() => { | ||
fallbackRef.current = fallback; | ||
}); | ||
useLayoutEffect(() => { | ||
return () => { | ||
var _a; | ||
(_a = controllerRef.current) === null || _a === void 0 ? void 0 : _a.abort(); | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
messageQueue.current = messageQueue.current | ||
.catch() | ||
.then(() => { var _a, _b; return (_b = (_a = hookRef.current) === null || _a === void 0 ? void 0 : _a.teardown) === null || _b === void 0 ? void 0 : _b.call(_a).then(() => { }); }) | ||
.catch((err) => { | ||
setError(() => { | ||
throw err; | ||
}); | ||
}); | ||
}; | ||
}, []); | ||
useLayoutEffect(() => { | ||
var _a; | ||
var _a, _b, _c; | ||
const existingHook = (_a = hookRef.current) === null || _a === void 0 ? void 0 : _a.params; | ||
const node = ref.current; | ||
if (lastNode.current === node) { | ||
return; | ||
if (existingHook) { | ||
if (existingHook.service === service && | ||
existingHook.node === node && | ||
existingHook.path === path && | ||
existingHook.type === type) { | ||
return; | ||
} | ||
} | ||
(_a = controllerRef.current) === null || _a === void 0 ? void 0 : _a.abort(); | ||
const controller = new AbortController(); | ||
controllerRef.current = controller; | ||
lastNode.current = ref.current; | ||
messageQueue.current = messageQueue.current | ||
const teardownPromise = messageQueue.current | ||
.catch() | ||
.then(() => service === null || service === void 0 ? void 0 : service.hook({ | ||
data: { | ||
hookId: hookId.current, | ||
node, | ||
type, | ||
path, | ||
}, | ||
}).then((response) => { | ||
var _a; | ||
if (!controller.signal.aborted) { | ||
if (response.errors) { | ||
if (response.errors.length === 1 && | ||
response.errors[0].code === "NOT_IMPLEMENTED") { | ||
teardownRef.current = (_a = fallbackRef.current(node)) !== null && _a !== void 0 ? _a : null; | ||
} | ||
else { | ||
// eslint-disable-next-line no-console | ||
console.error(response.errors); | ||
throw new Error("Unknown error in hook"); | ||
} | ||
} | ||
else if (response.data) { | ||
hookId.current = response.data.hookId; | ||
teardownRef.current = () => { | ||
messageQueue.current = messageQueue.current | ||
.catch() | ||
.then(() => service === null || service === void 0 ? void 0 : service.hook({ | ||
.then(() => { var _a, _b; return (_b = (_a = hookRef.current) === null || _a === void 0 ? void 0 : _a.teardown) === null || _b === void 0 ? void 0 : _b.call(_a).catch(); }); | ||
if (node && service) { | ||
const controller = new AbortController(); | ||
const reuseId = existingHook && | ||
existingHook.service === service && | ||
existingHook.path === path && | ||
existingHook.type === type; | ||
const hook = { | ||
id: reuseId ? (_c = (_b = hookRef.current) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : null : null, | ||
params: { | ||
service, | ||
type, | ||
path, | ||
node, | ||
}, | ||
teardown: () => __awaiter(void 0, void 0, void 0, function* () { | ||
controller.abort(); | ||
try { | ||
yield service.hook({ | ||
data: { | ||
hookId: hookId.current, | ||
hookId: hook.id, | ||
path, | ||
type, | ||
node: null, | ||
type, | ||
path, | ||
}, | ||
}).then(() => { })) | ||
.catch((err) => { | ||
if (!controller.signal.aborted) { | ||
setError(() => { | ||
throw err; | ||
}); | ||
} | ||
catch (err) { | ||
setError(() => { | ||
throw err; | ||
}); | ||
} | ||
}), | ||
}; | ||
messageQueue.current = teardownPromise.then(() => { | ||
return service | ||
.hook({ | ||
data: { | ||
hookId: hook.id, | ||
node, | ||
type, | ||
path, | ||
}, | ||
}) | ||
.then((response) => { | ||
if (!controller.signal.aborted) { | ||
if (response.errors) { | ||
if (response.errors.length === 1 && | ||
response.errors[0].code === "NOT_IMPLEMENTED") { | ||
const teardown = fallbackRef.current(node); | ||
hook.teardown = () => __awaiter(void 0, void 0, void 0, function* () { | ||
controller.abort(); | ||
yield (teardown === null || teardown === void 0 ? void 0 : teardown()); | ||
}); | ||
} | ||
}); | ||
}; | ||
} | ||
} | ||
})) | ||
.catch((err) => { | ||
setError(() => { | ||
throw err; | ||
else { | ||
// eslint-disable-next-line no-console | ||
console.error(response.errors); | ||
throw new Error("Unknown error in hook"); | ||
} | ||
} | ||
else if (response.data) { | ||
hook.id = response.data.hookId; | ||
} | ||
} | ||
}) | ||
.catch((err) => { | ||
setError(() => { | ||
throw err; | ||
}); | ||
}); | ||
}); | ||
}); | ||
return () => { | ||
var _a; | ||
(_a = teardownRef.current) === null || _a === void 0 ? void 0 : _a.call(teardownRef); | ||
teardownRef.current = null; | ||
}; | ||
} | ||
else { | ||
hookRef.current = null; | ||
} | ||
}); | ||
@@ -135,0 +174,0 @@ }; |
{ | ||
"name": "@blockprotocol/hook", | ||
"version": "0.0.1-canary.3", | ||
"version": "0.0.1-canary.4", | ||
"description": "Implementation of the Block Protocol Hook service specification for blocks and embedding applications", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
59613
965