@notchapp/api 0.1.0 → 0.1.1
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 +44 -20
- package/functions/openURL.js +9 -0
- package/hooks/useFetch.js +22 -0
- package/hooks/useLocalStorage.js +36 -0
- package/hooks/usePromise.js +96 -0
- package/index.js +121 -99
- package/jsx-runtime.js +3 -28
- package/package.json +5 -2
- package/runtime.js +34 -0
package/README.md
CHANGED
|
@@ -11,27 +11,18 @@ npm install @notchapp/api
|
|
|
11
11
|
Use it in a widget:
|
|
12
12
|
|
|
13
13
|
```tsx
|
|
14
|
-
import { Button, Stack, Text } from "@notchapp/api";
|
|
15
|
-
|
|
16
|
-
export
|
|
17
|
-
count
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
increment(state) {
|
|
22
|
-
return {
|
|
23
|
-
...state,
|
|
24
|
-
count: (state?.count ?? 0) + 1,
|
|
25
|
-
};
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export default function Widget({ environment, state }) {
|
|
14
|
+
import { Button, Stack, Text, useLocalStorage } from "@notchapp/api";
|
|
15
|
+
|
|
16
|
+
export default function Widget({ environment, logger }) {
|
|
17
|
+
const [count, setCount] = useLocalStorage("count", 0);
|
|
18
|
+
|
|
19
|
+
logger.info(`render hello widget span=${environment.span} count=${count}`);
|
|
20
|
+
|
|
30
21
|
return (
|
|
31
22
|
<Stack spacing={10}>
|
|
32
23
|
<Text>Hello from NotchApp</Text>
|
|
33
|
-
<Text tone="secondary">{`Span ${environment.span} • Count ${
|
|
34
|
-
<Button title="Increment"
|
|
24
|
+
<Text tone="secondary">{`Span ${environment.span} • Count ${count}`}</Text>
|
|
25
|
+
<Button title="Increment" onPress={() => setCount((value) => value + 1)} />
|
|
35
26
|
</Stack>
|
|
36
27
|
);
|
|
37
28
|
}
|
|
@@ -41,14 +32,47 @@ Current exports:
|
|
|
41
32
|
|
|
42
33
|
- `Stack`
|
|
43
34
|
- `Inline`
|
|
44
|
-
- `
|
|
35
|
+
- `Spacer`
|
|
45
36
|
- `Text`
|
|
46
37
|
- `Icon`
|
|
38
|
+
- `Image`
|
|
39
|
+
- `Button`
|
|
40
|
+
- `Row`
|
|
47
41
|
- `IconButton`
|
|
48
42
|
- `Checkbox`
|
|
49
43
|
- `Input`
|
|
50
|
-
- `
|
|
44
|
+
- `ScrollView`
|
|
45
|
+
- `Divider`
|
|
46
|
+
- `Circle`
|
|
47
|
+
- `RoundedRect`
|
|
48
|
+
- `LocalStorage`
|
|
49
|
+
- `getPreferenceValues`
|
|
50
|
+
- `useLocalStorage`
|
|
51
|
+
- `usePromise`
|
|
52
|
+
- `useFetch`
|
|
53
|
+
- `openURL`
|
|
54
|
+
|
|
55
|
+
Widget preferences can be declared in your widget manifest under `notch.preferences` and read at runtime:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { getPreferenceValues } from "@notchapp/api";
|
|
59
|
+
|
|
60
|
+
export default function Widget() {
|
|
61
|
+
const preferences = getPreferenceValues();
|
|
62
|
+
return <Text>{preferences.mailbox ?? "Inbox"}</Text>;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
51
65
|
|
|
52
66
|
The SDK source and examples live in the main repository:
|
|
53
67
|
|
|
54
68
|
<https://github.com/itstauq/NotchApp>
|
|
69
|
+
|
|
70
|
+
Local widget images live under your package `assets/` directory and can be referenced with paths like `src="assets/cover.png"`.
|
|
71
|
+
|
|
72
|
+
`Image` supports both local package assets and remote image URLs. `contentMode="fill"` is the default, and `contentMode="fit"` keeps the full image visible inside its frame.
|
|
73
|
+
|
|
74
|
+
Remote image notes:
|
|
75
|
+
|
|
76
|
+
- widgets use `https://` URLs only
|
|
77
|
+
- remote images are fetched by the host, not inside the widget runtime
|
|
78
|
+
- custom headers, cookies, and auth are not supported yet
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const { usePromise } = require("./usePromise");
|
|
2
|
+
|
|
3
|
+
function useFetch(url, options = {}) {
|
|
4
|
+
const { parseJson = true, ...requestInit } = options;
|
|
5
|
+
|
|
6
|
+
return usePromise(async (signal) => {
|
|
7
|
+
const response = await fetch(url, {
|
|
8
|
+
...requestInit,
|
|
9
|
+
signal,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
if (!response.ok) {
|
|
13
|
+
throw new Error(`Request failed with status ${response.status}`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return parseJson ? response.json() : response.text();
|
|
17
|
+
}, [url, JSON.stringify(options)]);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = {
|
|
21
|
+
useFetch,
|
|
22
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const React = require("react");
|
|
2
|
+
|
|
3
|
+
const { LocalStorage } = require("../runtime");
|
|
4
|
+
|
|
5
|
+
function useLocalStorage(key, defaultValue) {
|
|
6
|
+
const [value, setValue] = React.useState(() => {
|
|
7
|
+
const storedValue = LocalStorage.getItem(key);
|
|
8
|
+
return storedValue === undefined ? defaultValue : storedValue;
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
React.useEffect(() => {
|
|
12
|
+
const storedValue = LocalStorage.getItem(key);
|
|
13
|
+
setValue(storedValue === undefined ? defaultValue : storedValue);
|
|
14
|
+
}, [key]);
|
|
15
|
+
|
|
16
|
+
function setStoredValue(nextValue) {
|
|
17
|
+
setValue((currentValue) => {
|
|
18
|
+
const resolvedValue = typeof nextValue === "function"
|
|
19
|
+
? nextValue(currentValue)
|
|
20
|
+
: nextValue;
|
|
21
|
+
|
|
22
|
+
if (resolvedValue === undefined) {
|
|
23
|
+
LocalStorage.removeItem(key);
|
|
24
|
+
return defaultValue;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return LocalStorage.setItem(key, resolvedValue);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return [value, setStoredValue];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = {
|
|
35
|
+
useLocalStorage,
|
|
36
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const React = require("react");
|
|
2
|
+
|
|
3
|
+
function areDepsEqual(previousDeps, nextDeps) {
|
|
4
|
+
if (!previousDeps || !nextDeps || previousDeps.length !== nextDeps.length) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
for (let index = 0; index < previousDeps.length; index += 1) {
|
|
9
|
+
if (!Object.is(previousDeps[index], nextDeps[index])) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function usePromise(factory, deps = []) {
|
|
18
|
+
const [state, setState] = React.useState({
|
|
19
|
+
data: undefined,
|
|
20
|
+
isLoading: true,
|
|
21
|
+
error: undefined,
|
|
22
|
+
});
|
|
23
|
+
const controllerRef = React.useRef(null);
|
|
24
|
+
const factoryRef = React.useRef(factory);
|
|
25
|
+
const depsRef = React.useRef();
|
|
26
|
+
|
|
27
|
+
factoryRef.current = factory;
|
|
28
|
+
|
|
29
|
+
const revalidate = React.useCallback(() => {
|
|
30
|
+
controllerRef.current?.abort();
|
|
31
|
+
const controller = new AbortController();
|
|
32
|
+
controllerRef.current = controller;
|
|
33
|
+
|
|
34
|
+
setState((currentState) => ({
|
|
35
|
+
data: currentState.data,
|
|
36
|
+
isLoading: true,
|
|
37
|
+
error: undefined,
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
Promise.resolve()
|
|
41
|
+
.then(() => factoryRef.current(controller.signal))
|
|
42
|
+
.then((data) => {
|
|
43
|
+
if (controller.signal.aborted || controllerRef.current !== controller) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
setState({
|
|
48
|
+
data,
|
|
49
|
+
isLoading: false,
|
|
50
|
+
error: undefined,
|
|
51
|
+
});
|
|
52
|
+
})
|
|
53
|
+
.catch((error) => {
|
|
54
|
+
if (controller.signal.aborted || controllerRef.current !== controller) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (error?.name === "AbortError") {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
setState({
|
|
63
|
+
data: undefined,
|
|
64
|
+
isLoading: false,
|
|
65
|
+
error,
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}, []);
|
|
69
|
+
|
|
70
|
+
React.useEffect(() => {
|
|
71
|
+
const depsChanged = !areDepsEqual(depsRef.current, deps);
|
|
72
|
+
depsRef.current = deps;
|
|
73
|
+
if (!depsChanged) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
revalidate();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
React.useEffect(() => {
|
|
81
|
+
return () => {
|
|
82
|
+
controllerRef.current?.abort();
|
|
83
|
+
};
|
|
84
|
+
}, []);
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
data: state.data,
|
|
88
|
+
isLoading: state.isLoading,
|
|
89
|
+
error: state.error,
|
|
90
|
+
revalidate,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = {
|
|
95
|
+
usePromise,
|
|
96
|
+
};
|
package/index.js
CHANGED
|
@@ -1,139 +1,161 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
const React = require("react");
|
|
2
|
+
const { useLocalStorage } = require("./hooks/useLocalStorage");
|
|
3
|
+
const { usePromise } = require("./hooks/usePromise");
|
|
4
|
+
const { useFetch } = require("./hooks/useFetch");
|
|
5
|
+
const { openURL } = require("./functions/openURL");
|
|
6
|
+
const { LocalStorage, getPreferenceValues } = require("./runtime");
|
|
7
|
+
|
|
8
|
+
const OVERLAY_SLOT_TYPE = "__notch_overlay";
|
|
9
|
+
const LEADING_ACCESSORY_SLOT_TYPE = "__notch_leadingAccessory";
|
|
10
|
+
const TRAILING_ACCESSORY_SLOT_TYPE = "__notch_trailingAccessory";
|
|
11
|
+
|
|
12
|
+
function slot(type, props, children, key) {
|
|
13
|
+
return React.createElement(
|
|
14
|
+
type,
|
|
15
|
+
key == null ? props : { ...(props ?? {}), key },
|
|
16
|
+
children
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function normalizeOverlayChildren(overlay) {
|
|
21
|
+
if (overlay == null || overlay === false) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (Array.isArray(overlay)) {
|
|
26
|
+
return overlay.flatMap(normalizeOverlayChildren);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (React.isValidElement(overlay)) {
|
|
30
|
+
return [slot(OVERLAY_SLOT_TYPE, { alignment: "center" }, overlay, overlay.key)];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (typeof overlay === "object") {
|
|
34
|
+
const node = overlay.element ?? overlay.node;
|
|
35
|
+
if (node != null) {
|
|
36
|
+
return [
|
|
37
|
+
slot(
|
|
38
|
+
OVERLAY_SLOT_TYPE,
|
|
39
|
+
{ alignment: typeof overlay.alignment === "string" ? overlay.alignment : "center" },
|
|
40
|
+
node,
|
|
41
|
+
overlay.key ?? node.key
|
|
42
|
+
),
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return [];
|
|
5
48
|
}
|
|
6
49
|
|
|
7
|
-
function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
})
|
|
14
|
-
.join("");
|
|
50
|
+
function normalizeAccessoryChild(type, accessory) {
|
|
51
|
+
if (accessory == null || accessory === false) {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return [slot(type, null, accessory)];
|
|
15
56
|
}
|
|
16
57
|
|
|
17
|
-
function
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
58
|
+
function createHostElement(type, rawProps = {}) {
|
|
59
|
+
const {
|
|
60
|
+
children,
|
|
61
|
+
overlay,
|
|
62
|
+
leadingAccessory,
|
|
63
|
+
trailingAccessory,
|
|
64
|
+
...props
|
|
65
|
+
} = rawProps;
|
|
66
|
+
const hostChildren = [];
|
|
67
|
+
|
|
68
|
+
if (children !== undefined) {
|
|
69
|
+
hostChildren.push(children);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
hostChildren.push(...normalizeOverlayChildren(overlay));
|
|
73
|
+
hostChildren.push(...normalizeAccessoryChild(LEADING_ACCESSORY_SLOT_TYPE, leadingAccessory));
|
|
74
|
+
hostChildren.push(...normalizeAccessoryChild(TRAILING_ACCESSORY_SLOT_TYPE, trailingAccessory));
|
|
75
|
+
|
|
76
|
+
return React.createElement(type, props, ...hostChildren);
|
|
22
77
|
}
|
|
23
78
|
|
|
24
79
|
function Stack(props = {}) {
|
|
25
|
-
return
|
|
26
|
-
id: props.id ?? undefined,
|
|
27
|
-
type: "Stack",
|
|
28
|
-
direction: props.direction ?? "vertical",
|
|
29
|
-
spacing: props.spacing ?? 8,
|
|
30
|
-
children: flattenChildren(props.children),
|
|
31
|
-
};
|
|
80
|
+
return createHostElement("Stack", props);
|
|
32
81
|
}
|
|
33
82
|
|
|
34
83
|
function Inline(props = {}) {
|
|
35
|
-
return
|
|
36
|
-
id: props.id ?? undefined,
|
|
37
|
-
type: "Inline",
|
|
38
|
-
spacing: props.spacing ?? 8,
|
|
39
|
-
children: flattenChildren(props.children),
|
|
40
|
-
};
|
|
84
|
+
return createHostElement("Inline", props);
|
|
41
85
|
}
|
|
42
86
|
|
|
43
|
-
function
|
|
44
|
-
return
|
|
45
|
-
id: props.id ?? undefined,
|
|
46
|
-
type: "Row",
|
|
47
|
-
action: props.action ?? null,
|
|
48
|
-
payload: props.payload ?? null,
|
|
49
|
-
children: flattenChildren(props.children),
|
|
50
|
-
};
|
|
87
|
+
function Spacer(props = {}) {
|
|
88
|
+
return createHostElement("Spacer", props);
|
|
51
89
|
}
|
|
52
90
|
|
|
53
91
|
function Text(props = {}) {
|
|
54
|
-
return
|
|
55
|
-
id: props.id ?? undefined,
|
|
56
|
-
type: "Text",
|
|
57
|
-
text: props.text ?? extractText(props.children),
|
|
58
|
-
role: props.role ?? undefined,
|
|
59
|
-
tone: props.tone ?? undefined,
|
|
60
|
-
lineClamp: props.lineClamp ?? undefined,
|
|
61
|
-
strikethrough: props.strikethrough ?? undefined,
|
|
62
|
-
children: [],
|
|
63
|
-
};
|
|
92
|
+
return createHostElement("Text", props);
|
|
64
93
|
}
|
|
65
94
|
|
|
66
95
|
function Icon(props = {}) {
|
|
67
|
-
return
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
96
|
+
return createHostElement("Icon", props);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function Image(props = {}) {
|
|
100
|
+
return createHostElement("Image", props);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function Button(props = {}) {
|
|
104
|
+
return createHostElement("Button", props);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function Row(props = {}) {
|
|
108
|
+
return createHostElement("Row", props);
|
|
74
109
|
}
|
|
75
110
|
|
|
76
111
|
function IconButton(props = {}) {
|
|
77
|
-
return
|
|
78
|
-
id: props.id ?? undefined,
|
|
79
|
-
type: "IconButton",
|
|
80
|
-
symbol: props.symbol ?? props.icon ?? props.name ?? undefined,
|
|
81
|
-
action: props.action ?? null,
|
|
82
|
-
payload: props.payload ?? null,
|
|
83
|
-
tone: props.tone ?? undefined,
|
|
84
|
-
disabled: props.disabled ?? false,
|
|
85
|
-
children: [],
|
|
86
|
-
};
|
|
112
|
+
return createHostElement("IconButton", props);
|
|
87
113
|
}
|
|
88
114
|
|
|
89
115
|
function Checkbox(props = {}) {
|
|
90
|
-
return
|
|
91
|
-
id: props.id ?? undefined,
|
|
92
|
-
type: "Checkbox",
|
|
93
|
-
checked: props.checked ?? false,
|
|
94
|
-
action: props.action ?? null,
|
|
95
|
-
payload: props.payload ?? null,
|
|
96
|
-
children: [],
|
|
97
|
-
};
|
|
116
|
+
return createHostElement("Checkbox", props);
|
|
98
117
|
}
|
|
99
118
|
|
|
100
119
|
function Input(props = {}) {
|
|
101
|
-
return
|
|
102
|
-
id: props.id ?? undefined,
|
|
103
|
-
type: "Input",
|
|
104
|
-
value: props.value ?? "",
|
|
105
|
-
placeholder: props.placeholder ?? "",
|
|
106
|
-
changeAction: props.changeAction ?? null,
|
|
107
|
-
submitAction: props.submitAction ?? null,
|
|
108
|
-
leadingAccessory: wrapNode(props.leadingAccessory),
|
|
109
|
-
trailingAccessory: wrapNode(props.trailingAccessory),
|
|
110
|
-
children: [],
|
|
111
|
-
};
|
|
120
|
+
return createHostElement("Input", props);
|
|
112
121
|
}
|
|
113
122
|
|
|
114
|
-
function
|
|
115
|
-
return
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
+
function ScrollView(props = {}) {
|
|
124
|
+
return createHostElement("ScrollView", props);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function Divider(props = {}) {
|
|
128
|
+
return createHostElement("Divider", props);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function Circle(props = {}) {
|
|
132
|
+
return createHostElement("Circle", props);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function RoundedRect(props = {}) {
|
|
136
|
+
return createHostElement("RoundedRect", props);
|
|
123
137
|
}
|
|
124
138
|
|
|
125
139
|
module.exports = {
|
|
126
140
|
Stack,
|
|
127
141
|
Inline,
|
|
128
|
-
|
|
142
|
+
Spacer,
|
|
129
143
|
Text,
|
|
130
144
|
Icon,
|
|
145
|
+
Image,
|
|
146
|
+
Button,
|
|
147
|
+
Row,
|
|
131
148
|
IconButton,
|
|
132
149
|
Checkbox,
|
|
133
150
|
Input,
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
151
|
+
ScrollView,
|
|
152
|
+
Divider,
|
|
153
|
+
Circle,
|
|
154
|
+
RoundedRect,
|
|
155
|
+
LocalStorage,
|
|
156
|
+
getPreferenceValues,
|
|
157
|
+
useLocalStorage,
|
|
158
|
+
usePromise,
|
|
159
|
+
useFetch,
|
|
160
|
+
openURL,
|
|
139
161
|
};
|
package/jsx-runtime.js
CHANGED
|
@@ -1,28 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
function jsx(type, props, key) {
|
|
6
|
-
if (type === Fragment) {
|
|
7
|
-
return __internal.flattenChildren(props?.children);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const merged = { ...(props ?? {}) };
|
|
11
|
-
if (key != null && merged.id == null) {
|
|
12
|
-
merged.id = String(key);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (typeof type === "function") {
|
|
16
|
-
return type(merged);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
throw new Error(`Unsupported JSX type: ${String(type)}`);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const jsxs = jsx;
|
|
23
|
-
|
|
24
|
-
module.exports = {
|
|
25
|
-
Fragment,
|
|
26
|
-
jsx,
|
|
27
|
-
jsxs,
|
|
28
|
-
};
|
|
1
|
+
// Keep JSX bound to the @notchapp/api namespace so we can evolve this seam
|
|
2
|
+
// later without changing widget build configuration or source imports.
|
|
3
|
+
module.exports = require("react/jsx-runtime");
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@notchapp/api",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Widget component API for building NotchApp widgets",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
7
7
|
"index.js",
|
|
8
|
-
"jsx-runtime.js"
|
|
8
|
+
"jsx-runtime.js",
|
|
9
|
+
"runtime.js",
|
|
10
|
+
"hooks",
|
|
11
|
+
"functions"
|
|
9
12
|
],
|
|
10
13
|
"keywords": [
|
|
11
14
|
"notchapp",
|
package/runtime.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
function runtime() {
|
|
2
|
+
if (!globalThis.__NOTCH_RUNTIME__) {
|
|
3
|
+
throw new Error("@notchapp/api must run inside the Notch widget runtime");
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
return globalThis.__NOTCH_RUNTIME__;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
LocalStorage: {
|
|
11
|
+
getItem(key) {
|
|
12
|
+
return runtime().localStorage.getItem(key);
|
|
13
|
+
},
|
|
14
|
+
setItem(key, value) {
|
|
15
|
+
return runtime().localStorage.setItem(key, value);
|
|
16
|
+
},
|
|
17
|
+
removeItem(key) {
|
|
18
|
+
return runtime().localStorage.removeItem(key);
|
|
19
|
+
},
|
|
20
|
+
allItems() {
|
|
21
|
+
return runtime().localStorage.allItems();
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
getPreferenceValues() {
|
|
25
|
+
const preferences = runtime().getCurrentProps()?.preferences;
|
|
26
|
+
if (!preferences || typeof preferences !== "object" || Array.isArray(preferences)) {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return structuredClone(preferences);
|
|
31
|
+
},
|
|
32
|
+
getCurrentProps: () => runtime().getCurrentProps(),
|
|
33
|
+
callRpc: (method, params) => runtime().callRpc(method, params),
|
|
34
|
+
};
|