@lightningtv/solid 3.0.0-19 → 3.0.0-20
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/dist/src/primitives/Lazy.d.ts +1 -0
- package/dist/src/primitives/Lazy.jsx +14 -1
- package/dist/src/primitives/Lazy.jsx.map +1 -1
- package/dist/src/primitives/Virtual.jsx +7 -1
- package/dist/src/primitives/Virtual.jsx.map +1 -1
- package/dist/src/primitives/announcer/announcer.d.ts +1 -0
- package/dist/src/primitives/announcer/announcer.js +4 -3
- package/dist/src/primitives/announcer/announcer.js.map +1 -1
- package/dist/src/primitives/announcer/speech.d.ts +1 -1
- package/dist/src/primitives/announcer/speech.js +98 -8
- package/dist/src/primitives/announcer/speech.js.map +1 -1
- package/dist/src/primitives/createTag.d.ts +8 -0
- package/dist/src/primitives/createTag.jsx +20 -0
- package/dist/src/primitives/createTag.jsx.map +1 -0
- package/dist/src/primitives/index.d.ts +2 -0
- package/dist/src/primitives/index.js +2 -0
- package/dist/src/primitives/index.js.map +1 -1
- package/dist/src/primitives/useMouse.d.ts +18 -1
- package/dist/src/primitives/useMouse.js +142 -59
- package/dist/src/primitives/useMouse.js.map +1 -1
- package/dist/src/primitives/utils/createBlurredImage.d.ts +56 -0
- package/dist/src/primitives/utils/createBlurredImage.js +223 -0
- package/dist/src/primitives/utils/createBlurredImage.js.map +1 -0
- package/dist/src/primitives/utils/handleNavigation.js +7 -13
- package/dist/src/primitives/utils/handleNavigation.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -5
- package/src/primitives/Lazy.tsx +15 -3
- package/src/primitives/Virtual.tsx +8 -1
- package/src/primitives/announcer/announcer.ts +10 -3
- package/src/primitives/announcer/speech.ts +113 -6
- package/src/primitives/createTag.tsx +31 -0
- package/src/primitives/index.ts +2 -0
- package/src/primitives/useMouse.ts +253 -81
- package/src/primitives/utils/createBlurredImage.ts +366 -0
- package/src/primitives/utils/handleNavigation.ts +9 -14
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
import { ElementNode, activeElement, isElementNode, isTextNode, rootNode,
|
|
1
|
+
import { Config, ElementNode, activeElement, isElementNode, isFunc, isTextNode, rootNode, } from '@lightningtv/solid';
|
|
2
2
|
import { makeEventListener } from '@solid-primitives/event-listener';
|
|
3
3
|
import { useMousePosition } from '@solid-primitives/mouse';
|
|
4
4
|
import { createScheduled, throttle } from '@solid-primitives/scheduled';
|
|
5
|
-
import { createEffect } from 'solid-js';
|
|
5
|
+
import { createEffect, getOwner, runWithOwner } from 'solid-js';
|
|
6
|
+
const DEFAULT_PRESSED_STATE_DURATION = 150;
|
|
7
|
+
export function addCustomStateToElement(element, state) {
|
|
8
|
+
element.states?.add(state);
|
|
9
|
+
}
|
|
10
|
+
export function removeCustomStateFromElement(element, state) {
|
|
11
|
+
element?.states?.remove(state);
|
|
12
|
+
}
|
|
13
|
+
export function hasCustomState(element, state) {
|
|
14
|
+
return element.states?.has(state);
|
|
15
|
+
}
|
|
6
16
|
function createKeyboardEvent(key, keyCode, eventName = 'keydown') {
|
|
7
17
|
return new KeyboardEvent(eventName, {
|
|
8
18
|
key,
|
|
@@ -32,33 +42,105 @@ const handleScroll = throttle((e) => {
|
|
|
32
42
|
document.body.dispatchEvent(createKeyboardEvent('ArrowDown', 40, 'keyup'));
|
|
33
43
|
}, 250);
|
|
34
44
|
}, 250);
|
|
35
|
-
|
|
45
|
+
function findElementWithCustomState(myApp, x, y, customState) {
|
|
46
|
+
const result = getChildrenByPosition(myApp, x, y).filter((el) => hasCustomState(el, customState));
|
|
47
|
+
if (result.length === 0) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
let element = result[result.length - 1];
|
|
51
|
+
while (element) {
|
|
52
|
+
const elmParent = element.parent;
|
|
53
|
+
if (elmParent?.forwardStates && hasCustomState(elmParent, customState)) {
|
|
54
|
+
element = elmParent;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return element;
|
|
61
|
+
}
|
|
62
|
+
function findElementByActiveElement(e) {
|
|
36
63
|
const active = activeElement();
|
|
37
64
|
const precision = Config.rendererOptions?.deviceLogicalPixelRatio || 1;
|
|
38
65
|
if (active instanceof ElementNode &&
|
|
39
66
|
testCollision(e.clientX, e.clientY, (active.lng.absX || 0) * precision, (active.lng.absY || 0) * precision, (active.width || 0) * precision, (active.height || 0) * precision)) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
67
|
+
return active;
|
|
68
|
+
}
|
|
69
|
+
let parent = active?.parent;
|
|
70
|
+
while (parent) {
|
|
71
|
+
if (isFunc(parent.onMouseClick) &&
|
|
72
|
+
active &&
|
|
73
|
+
testCollision(e.clientX, e.clientY, (parent.lng.absX || 0) * precision, (parent.lng.absY || 0) * precision, (parent.width || 0) * precision, (parent.height || 0) * precision)) {
|
|
74
|
+
return parent;
|
|
43
75
|
}
|
|
76
|
+
parent = parent.parent;
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
function applyPressedState(element, pressedState, pressedStateDuration = DEFAULT_PRESSED_STATE_DURATION) {
|
|
81
|
+
addCustomStateToElement(element, pressedState);
|
|
82
|
+
setTimeout(() => {
|
|
83
|
+
removeCustomStateFromElement(element, pressedState);
|
|
84
|
+
}, pressedStateDuration);
|
|
85
|
+
}
|
|
86
|
+
function handleElementClick(clickedElement, e, customStates) {
|
|
87
|
+
if (customStates?.pressedState) {
|
|
88
|
+
applyPressedState(clickedElement, customStates.pressedState, customStates.pressedStateDuration);
|
|
89
|
+
}
|
|
90
|
+
if (isFunc(clickedElement.onMouseClick)) {
|
|
91
|
+
clickedElement.onMouseClick(e, clickedElement);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
else if (isFunc(clickedElement.onEnter)) {
|
|
95
|
+
clickedElement.onEnter();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
clickedElement.setFocus();
|
|
99
|
+
setTimeout(() => {
|
|
44
100
|
document.dispatchEvent(createKeyboardEvent('Enter', 13));
|
|
45
101
|
setTimeout(() => document.body.dispatchEvent(createKeyboardEvent('Enter', 13, 'keyup')), 1);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
parent = parent.parent;
|
|
102
|
+
}, 1);
|
|
103
|
+
}
|
|
104
|
+
function createHandleClick(myApp, customStates) {
|
|
105
|
+
return (e) => {
|
|
106
|
+
const clickedElement = customStates
|
|
107
|
+
? findElementWithCustomState(myApp, e.clientX, e.clientY, customStates.hoverState)
|
|
108
|
+
: findElementByActiveElement(e);
|
|
109
|
+
if (!clickedElement) {
|
|
110
|
+
return;
|
|
56
111
|
}
|
|
57
|
-
|
|
58
|
-
};
|
|
112
|
+
handleElementClick(clickedElement, e, customStates);
|
|
113
|
+
};
|
|
114
|
+
}
|
|
59
115
|
function testCollision(px, py, cx, cy, cw = 0, ch = 0) {
|
|
60
116
|
return px >= cx && px <= cx + cw && py >= cy && py <= cy + ch;
|
|
61
117
|
}
|
|
118
|
+
function isNodeAtPosition(node, x, y, precision) {
|
|
119
|
+
if (!isElementNode(node)) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
return (node.alpha !== 0 &&
|
|
123
|
+
!node.skipFocus &&
|
|
124
|
+
testCollision(x, y, (node.lng.absX || 0) * precision, (node.lng.absY || 0) * precision, (node.width || 0) * precision, (node.height || 0) * precision));
|
|
125
|
+
}
|
|
126
|
+
function findHighestZIndexNode(nodes) {
|
|
127
|
+
if (nodes.length === 0) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
if (nodes.length === 1) {
|
|
131
|
+
return nodes[0];
|
|
132
|
+
}
|
|
133
|
+
let maxZIndex = -1;
|
|
134
|
+
let highestNode = undefined;
|
|
135
|
+
for (const node of nodes) {
|
|
136
|
+
const zIndex = node.zIndex ?? -1;
|
|
137
|
+
if (zIndex >= maxZIndex) {
|
|
138
|
+
maxZIndex = zIndex;
|
|
139
|
+
highestNode = node;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return highestNode;
|
|
143
|
+
}
|
|
62
144
|
function getChildrenByPosition(node, x, y) {
|
|
63
145
|
const result = [];
|
|
64
146
|
const precision = Config.rendererOptions?.deviceLogicalPixelRatio || 1;
|
|
@@ -66,72 +148,73 @@ function getChildrenByPosition(node, x, y) {
|
|
|
66
148
|
let queue = [node];
|
|
67
149
|
while (queue.length > 0) {
|
|
68
150
|
// Process nodes at the current level
|
|
69
|
-
const currentLevelNodes =
|
|
70
|
-
|
|
71
|
-
if (isElementNode(currentNode) &&
|
|
72
|
-
currentNode.alpha !== 0 &&
|
|
73
|
-
!currentNode.skipFocus &&
|
|
74
|
-
testCollision(x, y, (currentNode.lng.absX || 0) * precision, (currentNode.lng.absY || 0) * precision, (currentNode.width || 0) * precision, (currentNode.height || 0) * precision)) {
|
|
75
|
-
currentLevelNodes.push(currentNode);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
const size = currentLevelNodes.length;
|
|
79
|
-
if (size === 0) {
|
|
151
|
+
const currentLevelNodes = queue.filter((currentNode) => isNodeAtPosition(currentNode, x, y, precision));
|
|
152
|
+
if (currentLevelNodes.length === 0) {
|
|
80
153
|
break;
|
|
81
154
|
}
|
|
82
|
-
|
|
83
|
-
if (
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
let maxZIndex = -1;
|
|
88
|
-
for (const node of currentLevelNodes) {
|
|
89
|
-
const zIndex = node.zIndex ?? -1;
|
|
90
|
-
if (zIndex > maxZIndex) {
|
|
91
|
-
maxZIndex = zIndex;
|
|
92
|
-
highestZIndexNode = node;
|
|
93
|
-
}
|
|
94
|
-
else if (zIndex === maxZIndex) {
|
|
95
|
-
highestZIndexNode = node;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
if (highestZIndexNode && !isTextNode(highestZIndexNode)) {
|
|
100
|
-
result.push(highestZIndexNode);
|
|
101
|
-
queue = highestZIndexNode.children;
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
queue = [];
|
|
155
|
+
const highestZIndexNode = findHighestZIndexNode(currentLevelNodes);
|
|
156
|
+
if (!highestZIndexNode || isTextNode(highestZIndexNode)) {
|
|
157
|
+
break;
|
|
105
158
|
}
|
|
159
|
+
result.push(highestZIndexNode);
|
|
160
|
+
queue = highestZIndexNode.children;
|
|
106
161
|
}
|
|
107
162
|
return result;
|
|
108
163
|
}
|
|
109
|
-
export function useMouse(myApp = rootNode, throttleBy = 100) {
|
|
164
|
+
export function useMouse(myApp = rootNode, throttleBy = 100, options) {
|
|
110
165
|
const pos = useMousePosition();
|
|
111
166
|
const scheduled = createScheduled((fn) => throttle(fn, throttleBy));
|
|
167
|
+
let previousElement = null;
|
|
168
|
+
const customStates = options?.customStates;
|
|
169
|
+
const hoverState = customStates?.hoverState;
|
|
170
|
+
const handleClick = createHandleClick(myApp, customStates);
|
|
171
|
+
const owner = getOwner();
|
|
172
|
+
const handleClickContext = (e) => {
|
|
173
|
+
runWithOwner(owner, () => handleClick(e));
|
|
174
|
+
};
|
|
112
175
|
makeEventListener(window, 'wheel', handleScroll);
|
|
113
|
-
makeEventListener(window, 'click',
|
|
176
|
+
makeEventListener(window, 'click', handleClickContext);
|
|
114
177
|
createEffect(() => {
|
|
115
178
|
if (scheduled()) {
|
|
116
|
-
const result = getChildrenByPosition(myApp, pos.x, pos.y).filter((el) => el.
|
|
179
|
+
const result = getChildrenByPosition(myApp, pos.x, pos.y).filter((el) => !!(el.onEnter ||
|
|
180
|
+
el.onMouseClick ||
|
|
181
|
+
el.onFocus ||
|
|
182
|
+
el[Config.focusStateKey] ||
|
|
183
|
+
(hoverState ? el[hoverState] : false)));
|
|
117
184
|
if (result.length) {
|
|
118
185
|
let activeElm = result[result.length - 1];
|
|
119
186
|
while (activeElm) {
|
|
120
187
|
const elmParent = activeElm.parent;
|
|
121
188
|
if (elmParent?.forwardStates) {
|
|
122
|
-
activeElm =
|
|
189
|
+
activeElm = elmParent;
|
|
123
190
|
}
|
|
124
191
|
else {
|
|
125
192
|
break;
|
|
126
193
|
}
|
|
127
194
|
}
|
|
195
|
+
if (!activeElm) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
128
198
|
// Update Row & Column Selected property
|
|
129
|
-
const activeElmParent = activeElm
|
|
130
|
-
if (
|
|
199
|
+
const activeElmParent = activeElm.parent;
|
|
200
|
+
if (activeElmParent?.selected !== undefined) {
|
|
131
201
|
activeElmParent.selected =
|
|
132
202
|
activeElmParent.children.indexOf(activeElm);
|
|
133
203
|
}
|
|
134
|
-
activeElm
|
|
204
|
+
if (previousElement && previousElement !== activeElm && hoverState) {
|
|
205
|
+
removeCustomStateFromElement(previousElement, hoverState);
|
|
206
|
+
}
|
|
207
|
+
if (hoverState) {
|
|
208
|
+
addCustomStateToElement(activeElm, hoverState);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
activeElm.setFocus();
|
|
212
|
+
}
|
|
213
|
+
previousElement = activeElm;
|
|
214
|
+
}
|
|
215
|
+
else if (previousElement && hoverState) {
|
|
216
|
+
removeCustomStateFromElement(previousElement, hoverState);
|
|
217
|
+
previousElement = null;
|
|
135
218
|
}
|
|
136
219
|
}
|
|
137
220
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMouse.js","sourceRoot":"","sources":["../../../src/primitives/useMouse.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,aAAa,EACb,aAAa,EACb,UAAU,EACV,QAAQ,
|
|
1
|
+
{"version":3,"file":"useMouse.js","sourceRoot":"","sources":["../../../src/primitives/useMouse.ts"],"names":[],"mappings":"AACA,OAAO,EACL,MAAM,EACN,WAAW,EACX,aAAa,EACb,aAAa,EACb,MAAM,EACN,UAAU,EACV,QAAQ,GACT,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AA2BhE,MAAM,8BAA8B,GAAG,GAAG,CAAC;AAE3C,MAAM,UAAU,uBAAuB,CACrC,OAAuB,EACvB,KAAkB;IAElB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,OAAuB,EACvB,KAAkB;IAElB,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,OAAuB,EACvB,KAAkB;IAElB,OAAO,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,mBAAmB,CAC1B,GAAW,EACX,OAAe,EACf,YAAoB,SAAS;IAE7B,OAAO,IAAI,aAAa,CAAC,SAAS,EAAE;QAClC,GAAG;QACH,OAAO;QACP,KAAK,EAAE,OAAO;QACd,OAAO,EAAE,KAAK;QACd,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,IAAI;KACd,CAAC,CAAC;AACL,CAAC;AAED,IAAI,aAA4C,CAAC;AACjD,MAAM,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAa,EAAQ,EAAE;IACpD,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACxB,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QACf,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;IAClE,CAAC;SAAM,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,wDAAwD;IACxD,YAAY,CAAC,aAAa,CAAC,CAAC;IAC5B,+EAA+E;IAC/E,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE;QAC9B,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAAC,SAAS,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;QACzE,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAAC,WAAW,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7E,CAAC,EAAE,GAAG,CAAC,CAAC;AACV,CAAC,EAAE,GAAG,CAAC,CAAC;AAER,SAAS,0BAA0B,CACjC,KAAW,EACX,CAAS,EACT,CAAS,EACT,WAAwB;IAExB,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAC9D,cAAc,CAAC,EAAE,EAAE,WAAW,CAAC,CAChC,CAAC;IAEF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,OAAO,GAA4B,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEjE,OAAO,OAAO,EAAE,CAAC;QACf,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;QACjC,IAAI,SAAS,EAAE,aAAa,IAAI,cAAc,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;YACvE,OAAO,GAAG,SAAS,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,MAAM;QACR,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,0BAA0B,CAAC,CAAa;IAC/C,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAG,MAAM,CAAC,eAAe,EAAE,uBAAuB,IAAI,CAAC,CAAC;IAEvE,IACE,MAAM,YAAY,WAAW;QAC7B,aAAa,CACX,CAAC,CAAC,OAAO,EACT,CAAC,CAAC,OAAO,EACT,CAAE,MAAM,CAAC,GAAG,CAAC,IAAe,IAAI,CAAC,CAAC,GAAG,SAAS,EAC9C,CAAE,MAAM,CAAC,GAAG,CAAC,IAAe,IAAI,CAAC,CAAC,GAAG,SAAS,EAC9C,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,SAAS,EAC/B,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,SAAS,CACjC,EACD,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC;IAC5B,OAAO,MAAM,EAAE,CAAC;QACd,IACE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC;YAC3B,MAAM;YACN,aAAa,CACX,CAAC,CAAC,OAAO,EACT,CAAC,CAAC,OAAO,EACT,CAAE,MAAM,CAAC,GAAG,CAAC,IAAe,IAAI,CAAC,CAAC,GAAG,SAAS,EAC9C,CAAE,MAAM,CAAC,GAAG,CAAC,IAAe,IAAI,CAAC,CAAC,GAAG,SAAS,EAC9C,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,SAAS,EAC/B,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,SAAS,CACjC,EACD,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IACzB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,iBAAiB,CACxB,OAAoB,EACpB,YAAyB,EACzB,uBAA+B,8BAA8B;IAE7D,uBAAuB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC/C,UAAU,CAAC,GAAG,EAAE;QACd,4BAA4B,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACtD,CAAC,EAAE,oBAAoB,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,kBAAkB,CACzB,cAA2B,EAC3B,CAAa,EACb,YAAgC;IAEhC,IAAI,YAAY,EAAE,YAAY,EAAE,CAAC;QAC/B,iBAAiB,CACf,cAAc,EACd,YAAY,CAAC,YAAY,EACzB,YAAY,CAAC,oBAAoB,CAClC,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,cAAc,CAAC,YAAY,CAAC,EAAE,CAAC;QACxC,cAAc,CAAC,YAAY,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;QAC/C,OAAO;IACT,CAAC;SAAM,IAAI,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1C,cAAc,CAAC,OAAO,EAAE,CAAC;QACzB,OAAO;IACT,CAAC;IAED,cAAc,CAAC,QAAQ,EAAE,CAAC;IAC1B,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,CAAC,aAAa,CAAC,mBAAmB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;QACzD,UAAU,CACR,GAAG,EAAE,CACH,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,EACxE,CAAC,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,CAAC,CAAC;AACR,CAAC;AAED,SAAS,iBAAiB,CACxB,KAAW,EACX,YAAgC;IAEhC,OAAO,CAAC,CAAa,EAAQ,EAAE;QAC7B,MAAM,cAAc,GAAG,YAAY;YACjC,CAAC,CAAC,0BAA0B,CACxB,KAAK,EACL,CAAC,CAAC,OAAO,EACT,CAAC,CAAC,OAAO,EACT,YAAY,CAAC,UAAU,CACxB;YACH,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC;QAElC,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO;QACT,CAAC;QAED,kBAAkB,CAAC,cAAc,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;IACtD,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CACpB,EAAU,EACV,EAAU,EACV,EAAU,EACV,EAAU,EACV,KAAa,CAAC,EACd,KAAa,CAAC;IAEd,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AAChE,CAAC;AAED,SAAS,gBAAgB,CACvB,IAA0C,EAC1C,CAAS,EACT,CAAS,EACT,SAAiB;IAEjB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CACL,IAAI,CAAC,KAAK,KAAK,CAAC;QAChB,CAAC,IAAI,CAAC,SAAS;QACf,aAAa,CACX,CAAC,EACD,CAAC,EACD,CAAE,IAAI,CAAC,GAAG,CAAC,IAAe,IAAI,CAAC,CAAC,GAAG,SAAS,EAC5C,CAAE,IAAI,CAAC,GAAG,CAAC,IAAe,IAAI,CAAC,CAAC,GAAG,SAAS,EAC5C,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,SAAS,EAC7B,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,SAAS,CAC/B,CACF,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAoB;IACjD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC;IACnB,IAAI,WAAW,GAA4B,SAAS,CAAC;IAErD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;QACjC,IAAI,MAAM,IAAI,SAAS,EAAE,CAAC;YACxB,SAAS,GAAG,MAAM,CAAC;YACnB,WAAW,GAAG,IAAI,CAAC;QACrB,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,SAAS,qBAAqB,CAC5B,IAAc,EACd,CAAS,EACT,CAAS;IAET,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,eAAe,EAAE,uBAAuB,IAAI,CAAC,CAAC;IACvE,gBAAgB;IAEhB,IAAI,KAAK,GAA6C,CAAC,IAAI,CAAC,CAAC;IAE7D,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,qCAAqC;QACrC,MAAM,iBAAiB,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CACrD,gBAAgB,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAC/C,CAAC;QAEF,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM;QACR,CAAC;QAED,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,iBAAiB,CAAC,CAAC;QAEnE,IAAI,CAAC,iBAAiB,IAAI,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACxD,MAAM;QACR,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,iBAA6B,CAAC,CAAC;QAC3C,KAAK,GAAG,iBAAiB,CAAC,QAAQ,CAAC;IACrC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,QAAQ,CACtB,QAAc,QAAgB,EAC9B,aAAqB,GAAG,EACxB,OAAyB;IAEzB,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAG,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;IACpE,IAAI,eAAe,GAAuB,IAAI,CAAC;IAC/C,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY,CAAC;IAC3C,MAAM,UAAU,GAAG,YAAY,EAAE,UAAU,CAAC;IAC5C,MAAM,WAAW,GAAG,iBAAiB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IAC3D,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,kBAAkB,GAAG,CAAC,CAAa,EAAE,EAAE;QAC3C,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC,CAAC;IAEF,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;IACjD,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC;IACvD,YAAY,CAAC,GAAG,EAAE;QAChB,IAAI,SAAS,EAAE,EAAE,CAAC;YAChB,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAC9D,CAAC,EAAE,EAAE,EAAE,CACL,CAAC,CAAC,CACA,EAAE,CAAC,OAAO;gBACV,EAAE,CAAC,YAAY;gBACf,EAAE,CAAC,OAAO;gBACV,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC;gBACxB,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CACtC,CACJ,CAAC;YAEF,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAClB,IAAI,SAAS,GAA4B,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAEnE,OAAO,SAAS,EAAE,CAAC;oBACjB,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC;oBACnC,IAAI,SAAS,EAAE,aAAa,EAAE,CAAC;wBAC7B,SAAS,GAAG,SAAS,CAAC;oBACxB,CAAC;yBAAM,CAAC;wBACN,MAAM;oBACR,CAAC;gBACH,CAAC;gBAED,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,OAAO;gBACT,CAAC;gBAED,wCAAwC;gBACxC,MAAM,eAAe,GAAG,SAAS,CAAC,MAAM,CAAC;gBACzC,IAAI,eAAe,EAAE,QAAQ,KAAK,SAAS,EAAE,CAAC;oBAC5C,eAAe,CAAC,QAAQ;wBACtB,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBAChD,CAAC;gBAED,IAAI,eAAe,IAAI,eAAe,KAAK,SAAS,IAAI,UAAU,EAAE,CAAC;oBACnE,4BAA4B,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;gBAC5D,CAAC;gBAED,IAAI,UAAU,EAAE,CAAC;oBACf,uBAAuB,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;gBACjD,CAAC;qBAAM,CAAC;oBACN,SAAS,CAAC,QAAQ,EAAE,CAAC;gBACvB,CAAC;gBAED,eAAe,GAAG,SAAS,CAAC;YAC9B,CAAC;iBAAM,IAAI,eAAe,IAAI,UAAU,EAAE,CAAC;gBACzC,4BAA4B,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;gBAC1D,eAAe,GAAG,IAAI,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type Accessor, type Resource } from 'solid-js';
|
|
2
|
+
/**
|
|
3
|
+
* Represents a valid image source that can be used for blurring
|
|
4
|
+
*/
|
|
5
|
+
type ImageSource = string | URL;
|
|
6
|
+
/**
|
|
7
|
+
* Represents a valid image source or null/undefined
|
|
8
|
+
*/
|
|
9
|
+
type NullableImageSource = ImageSource | null | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Configuration options for Gaussian blur operation
|
|
12
|
+
*/
|
|
13
|
+
interface BlurOptions {
|
|
14
|
+
/**
|
|
15
|
+
* The blur radius in pixels
|
|
16
|
+
* @default 10
|
|
17
|
+
*/
|
|
18
|
+
readonly radius?: number;
|
|
19
|
+
/**
|
|
20
|
+
* CORS setting for image loading
|
|
21
|
+
* @default 'anonymous'
|
|
22
|
+
*/
|
|
23
|
+
readonly crossOrigin?: 'anonymous' | 'use-credentials' | '';
|
|
24
|
+
/**
|
|
25
|
+
* The resolution of the output image in pixels
|
|
26
|
+
* @default 1
|
|
27
|
+
*/
|
|
28
|
+
readonly resolution?: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Type for the resource return value from createBlurredImage
|
|
32
|
+
*/
|
|
33
|
+
type BlurredImageResource<T extends NullableImageSource> = Resource<T extends null | undefined ? null : string>;
|
|
34
|
+
/**
|
|
35
|
+
* Applies Gaussian blur to an image URL
|
|
36
|
+
* @param imageUrl - Image source (string or URL)
|
|
37
|
+
* @param options - Blur configuration options
|
|
38
|
+
* @returns Promise resolving to data URL of blurred image
|
|
39
|
+
* @throws {Error} If image fails to load or blur operation fails
|
|
40
|
+
*/
|
|
41
|
+
export declare function applyGaussianBlur<TSource extends ImageSource>(imageUrl: TSource, options?: Readonly<BlurOptions>): Promise<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Hook to create a blurred image resource
|
|
44
|
+
* @param imageUrl - Accessor function returning image source or null/undefined
|
|
45
|
+
* @param options - Blur configuration options
|
|
46
|
+
* @returns Resource containing blurred image data URL or null
|
|
47
|
+
* @template TSource - Type of image source (string, URL, or null/undefined)
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* const imageUrl = () => 'https://example.com/image.jpg';
|
|
52
|
+
* const blurred = createBlurredImage(imageUrl, { radius: 15 });
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function createBlurredImage<TSource extends NullableImageSource>(imageUrl: Accessor<TSource>, options?: Readonly<BlurOptions>): BlurredImageResource<TSource>;
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { createResource } from 'solid-js';
|
|
2
|
+
/**
|
|
3
|
+
* Default blur options
|
|
4
|
+
*/
|
|
5
|
+
const DEFAULT_BLUR_OPTIONS = {
|
|
6
|
+
radius: 10,
|
|
7
|
+
crossOrigin: 'anonymous',
|
|
8
|
+
resolution: 1,
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Validates that radius is a positive number
|
|
12
|
+
*/
|
|
13
|
+
function isValidRadius(radius) {
|
|
14
|
+
return radius > 0 && Number.isFinite(radius);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Ensures a resolution is a positive number
|
|
18
|
+
*/
|
|
19
|
+
function isValidResolution(resolution) {
|
|
20
|
+
return resolution > 0 && resolution <= 1 && Number.isFinite(resolution);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Applies vertical Gaussian blur to image data
|
|
24
|
+
* @param input - Input pixel data
|
|
25
|
+
* @param output - Output pixel data buffer
|
|
26
|
+
* @param width - Image width
|
|
27
|
+
* @param height - Image height
|
|
28
|
+
* @param kernel - Gaussian kernel weights
|
|
29
|
+
* @param half - Half of kernel size
|
|
30
|
+
*/
|
|
31
|
+
function applyVerticalBlur(input, output, width, height, kernel, half) {
|
|
32
|
+
for (let y = 0; y < height; y++) {
|
|
33
|
+
for (let x = 0; x < width; x++) {
|
|
34
|
+
let r = 0, g = 0, b = 0, a = 0;
|
|
35
|
+
let weightSum = 0;
|
|
36
|
+
for (let ky = -half; ky <= half; ky++) {
|
|
37
|
+
const py = y + ky;
|
|
38
|
+
if (py >= 0 && py < height) {
|
|
39
|
+
const pixelIndex = (py * width + x) * 4;
|
|
40
|
+
const weight = kernel[ky + half];
|
|
41
|
+
r += input[pixelIndex] * weight;
|
|
42
|
+
g += input[pixelIndex + 1] * weight;
|
|
43
|
+
b += input[pixelIndex + 2] * weight;
|
|
44
|
+
a += input[pixelIndex + 3] * weight;
|
|
45
|
+
weightSum += weight;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const outputIndex = (y * width + x) * 4;
|
|
49
|
+
output[outputIndex] = r / weightSum;
|
|
50
|
+
output[outputIndex + 1] = g / weightSum;
|
|
51
|
+
output[outputIndex + 2] = b / weightSum;
|
|
52
|
+
output[outputIndex + 3] = a / weightSum;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Applies horizontal Gaussian blur to image data
|
|
58
|
+
* @param input - Input pixel data
|
|
59
|
+
* @param output - Output pixel data buffer
|
|
60
|
+
* @param width - Image width
|
|
61
|
+
* @param height - Image height
|
|
62
|
+
* @param kernel - Gaussian kernel weights
|
|
63
|
+
* @param half - Half of kernel size
|
|
64
|
+
*/
|
|
65
|
+
function applyHorizontalBlur(input, output, width, height, kernel, half) {
|
|
66
|
+
for (let y = 0; y < height; y++) {
|
|
67
|
+
for (let x = 0; x < width; x++) {
|
|
68
|
+
let r = 0, g = 0, b = 0, a = 0;
|
|
69
|
+
let weightSum = 0;
|
|
70
|
+
for (let kx = -half; kx <= half; kx++) {
|
|
71
|
+
const px = x + kx;
|
|
72
|
+
if (px >= 0 && px < width) {
|
|
73
|
+
const pixelIndex = (y * width + px) * 4;
|
|
74
|
+
const weight = kernel[kx + half];
|
|
75
|
+
r += input[pixelIndex] * weight;
|
|
76
|
+
g += input[pixelIndex + 1] * weight;
|
|
77
|
+
b += input[pixelIndex + 2] * weight;
|
|
78
|
+
a += input[pixelIndex + 3] * weight;
|
|
79
|
+
weightSum += weight;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const outputIndex = (y * width + x) * 4;
|
|
83
|
+
output[outputIndex] = r / weightSum;
|
|
84
|
+
output[outputIndex + 1] = g / weightSum;
|
|
85
|
+
output[outputIndex + 2] = b / weightSum;
|
|
86
|
+
output[outputIndex + 3] = a / weightSum;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Generates a normalized Gaussian kernel
|
|
92
|
+
* @param size - Kernel size (must be odd)
|
|
93
|
+
* @param sigma - Standard deviation
|
|
94
|
+
* @returns Normalized Gaussian kernel
|
|
95
|
+
*/
|
|
96
|
+
function generateGaussianKernel(size, sigma) {
|
|
97
|
+
const kernel = [];
|
|
98
|
+
const half = Math.floor(size / 2);
|
|
99
|
+
let sum = 0;
|
|
100
|
+
for (let i = -half; i <= half; i++) {
|
|
101
|
+
const value = Math.exp(-(i * i) / (2 * sigma * sigma));
|
|
102
|
+
kernel.push(value);
|
|
103
|
+
sum += value;
|
|
104
|
+
}
|
|
105
|
+
return Object.freeze(kernel.map((value) => value / sum));
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Applies Gaussian blur convolution to image data
|
|
109
|
+
* @param imageData - Source image data
|
|
110
|
+
* @param dimensions - Image dimensions
|
|
111
|
+
* @param radius - Blur radius
|
|
112
|
+
* @returns Blurred image data
|
|
113
|
+
*/
|
|
114
|
+
function gaussianBlurConvolution(imageData, dimensions, radius) {
|
|
115
|
+
const { data } = imageData;
|
|
116
|
+
const { width, height } = dimensions;
|
|
117
|
+
const output = new Uint8ClampedArray(data.length);
|
|
118
|
+
const kernelSize = Math.ceil(radius * 2) * 2 + 1;
|
|
119
|
+
const kernel = generateGaussianKernel(kernelSize, radius);
|
|
120
|
+
const half = Math.floor(kernelSize / 2);
|
|
121
|
+
applyHorizontalBlur(data, output, width, height, kernel, half);
|
|
122
|
+
const tempData = new Uint8ClampedArray(output);
|
|
123
|
+
applyVerticalBlur(tempData, output, width, height, kernel, half);
|
|
124
|
+
return new ImageData(output, width, height);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Applies Gaussian blur to an image URL
|
|
128
|
+
* @param imageUrl - Image source (string or URL)
|
|
129
|
+
* @param options - Blur configuration options
|
|
130
|
+
* @returns Promise resolving to data URL of blurred image
|
|
131
|
+
* @throws {Error} If image fails to load or blur operation fails
|
|
132
|
+
*/
|
|
133
|
+
export async function applyGaussianBlur(imageUrl, options) {
|
|
134
|
+
const opts = { ...DEFAULT_BLUR_OPTIONS, ...options };
|
|
135
|
+
const radius = opts.radius;
|
|
136
|
+
const resolution = opts.resolution;
|
|
137
|
+
if (!isValidRadius(radius)) {
|
|
138
|
+
throw new Error(`Invalid blur radius: ${radius}. Must be a positive number.`);
|
|
139
|
+
}
|
|
140
|
+
if (!isValidResolution(resolution)) {
|
|
141
|
+
throw new Error(`Invalid resolution: ${resolution}. Must be a number between 0 and 1.`);
|
|
142
|
+
}
|
|
143
|
+
return new Promise((resolve, reject) => {
|
|
144
|
+
const img = new Image();
|
|
145
|
+
img.crossOrigin = opts.crossOrigin;
|
|
146
|
+
img.onload = () => {
|
|
147
|
+
try {
|
|
148
|
+
const canvas = document.createElement('canvas');
|
|
149
|
+
const ctx = canvas.getContext('2d', {
|
|
150
|
+
willReadFrequently: true,
|
|
151
|
+
});
|
|
152
|
+
if (ctx === null) {
|
|
153
|
+
reject(new Error('Failed to get canvas context'));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const scaledWidth = Math.max(1, Math.round(img.width * resolution));
|
|
157
|
+
const scaledHeight = Math.max(1, Math.round(img.height * resolution));
|
|
158
|
+
const dimensions = {
|
|
159
|
+
width: scaledWidth,
|
|
160
|
+
height: scaledHeight,
|
|
161
|
+
};
|
|
162
|
+
canvas.width = dimensions.width;
|
|
163
|
+
canvas.height = dimensions.height;
|
|
164
|
+
const hasFilterSupport = ctx.filter !== undefined;
|
|
165
|
+
if (hasFilterSupport) {
|
|
166
|
+
ctx.filter = `blur(${radius}px)`;
|
|
167
|
+
ctx.drawImage(img, 0, 0, scaledWidth, scaledHeight);
|
|
168
|
+
ctx.filter = 'none';
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
ctx.drawImage(img, 0, 0, scaledWidth, scaledHeight);
|
|
172
|
+
const imageData = ctx.getImageData(0, 0, dimensions.width, dimensions.height);
|
|
173
|
+
const blurredData = gaussianBlurConvolution(imageData, dimensions, radius);
|
|
174
|
+
ctx.putImageData(blurredData, 0, 0);
|
|
175
|
+
}
|
|
176
|
+
const dataUrl = canvas.toDataURL();
|
|
177
|
+
if (dataUrl) {
|
|
178
|
+
resolve(dataUrl);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
reject(new Error('Failed to create image data URL'));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
reject(error instanceof Error
|
|
186
|
+
? error
|
|
187
|
+
: new Error('Unknown error during blur operation'));
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
img.onerror = () => {
|
|
191
|
+
reject(new Error('Failed to load image'));
|
|
192
|
+
};
|
|
193
|
+
const srcString = typeof imageUrl === 'string' ? imageUrl : imageUrl.toString();
|
|
194
|
+
img.src = srcString;
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Hook to create a blurred image resource
|
|
199
|
+
* @param imageUrl - Accessor function returning image source or null/undefined
|
|
200
|
+
* @param options - Blur configuration options
|
|
201
|
+
* @returns Resource containing blurred image data URL or null
|
|
202
|
+
* @template TSource - Type of image source (string, URL, or null/undefined)
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```ts
|
|
206
|
+
* const imageUrl = () => 'https://example.com/image.jpg';
|
|
207
|
+
* const blurred = createBlurredImage(imageUrl, { radius: 15 });
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
export function createBlurredImage(imageUrl, options) {
|
|
211
|
+
const imageUrlString = () => {
|
|
212
|
+
const url = imageUrl();
|
|
213
|
+
if (url === null || url === undefined) {
|
|
214
|
+
return url;
|
|
215
|
+
}
|
|
216
|
+
return typeof url === 'string' ? url : url.toString();
|
|
217
|
+
};
|
|
218
|
+
const [blurredImage] = createResource(imageUrlString, async (url) => {
|
|
219
|
+
return await applyGaussianBlur(url, options);
|
|
220
|
+
});
|
|
221
|
+
return blurredImage;
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=createBlurredImage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createBlurredImage.js","sourceRoot":"","sources":["../../../../src/primitives/utils/createBlurredImage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as s from 'solid-js';
|
|
2
2
|
import * as lng from '@lightningtv/solid';
|
|
3
3
|
function idxInArray(idx, arr) {
|
|
4
|
-
return idx >= 0 && idx < arr.length;
|
|
4
|
+
return idx === 0 || (idx >= 0 && idx < arr.length);
|
|
5
5
|
}
|
|
6
6
|
function findFirstFocusableChildIdx(el, from = 0, delta = 1) {
|
|
7
7
|
for (let i = from;; i += delta) {
|
|
@@ -54,19 +54,13 @@ export function onGridFocus(_) {
|
|
|
54
54
|
*/
|
|
55
55
|
export const navigableForwardFocus = function () {
|
|
56
56
|
const navigable = this;
|
|
57
|
-
// Undo for now - We should only do this when setFocus is called rather than on forwardFocus
|
|
58
|
-
// needs some more research
|
|
59
|
-
// if (!lng.isFocused(this)) {
|
|
60
|
-
// // if a child already has focus, assume that should be selected
|
|
61
|
-
// for (let [i, child] of this.children.entries()) {
|
|
62
|
-
// if (lng.isFocused(child)) {
|
|
63
|
-
// this.selected = i;
|
|
64
|
-
// break;
|
|
65
|
-
// }
|
|
66
|
-
// }
|
|
67
|
-
// }
|
|
68
57
|
let selected = navigable.selected;
|
|
69
|
-
|
|
58
|
+
if (selected !== 0) {
|
|
59
|
+
selected = lng.clamp(selected, 0, this.children.length - 1);
|
|
60
|
+
while (!idxInArray(selected, this.children)) {
|
|
61
|
+
selected--;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
70
64
|
selected = findFirstFocusableChildIdx(navigable, selected);
|
|
71
65
|
// update selected as firstfocusable maybe different if first element has skipFocus
|
|
72
66
|
navigable.selected = selected;
|