@solidrt/components 0.0.9 → 0.0.11
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/AGENTS.md +67 -0
- package/README.md +2 -0
- package/package.json +3 -4
- package/src/image.tsx +40 -15
package/AGENTS.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# @solidrt/components - agent notes
|
|
2
|
+
|
|
3
|
+
Higher-level components built on @solidrt/core primitives. Optional: an app can
|
|
4
|
+
be built with core primitives alone. For the underlying element model, events,
|
|
5
|
+
reactivity, and how to run/verify, see @solidrt/core and @solidrt/cli (their
|
|
6
|
+
AGENTS.md). Full prop tables are in this package's README.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
bun add @solidrt/components # peers: @solidrt/core, @solidjs/signals
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Props: layout vs style (the non-obvious split)
|
|
15
|
+
|
|
16
|
+
Most components group props into two objects, plus top-level event handlers:
|
|
17
|
+
|
|
18
|
+
- `layout={{...}}` - the core LayoutProps: flex/grid, sizing, padding/margin,
|
|
19
|
+
position. For `Text`, also the font fields (fontSize, fontWeight, ...).
|
|
20
|
+
Changing these relayouts.
|
|
21
|
+
- `style={{...}}` - paint only, never affects layout: `backgroundColor`,
|
|
22
|
+
`borderColor`, `borderWidth`, `borderRadius`, `color` (Text), and the
|
|
23
|
+
transform `x`/`y`/`rotate`/`scale`.
|
|
24
|
+
- Event handlers (`onPointerDown`, `onKeyDown`, ...) are top-level props, NOT
|
|
25
|
+
inside `layout`/`style`.
|
|
26
|
+
|
|
27
|
+
## Exports
|
|
28
|
+
|
|
29
|
+
- `Window` - root surface; renders a core `<window>`, so `render()` accepts it.
|
|
30
|
+
Applies `layout` and `style.backgroundColor` only (a window cannot be
|
|
31
|
+
transformed or bordered). Also: `title`, `fullscreen`, `vsync`, `fps`.
|
|
32
|
+
- `View` - general box; draws a background/border when the matching `style`
|
|
33
|
+
props are set.
|
|
34
|
+
- `Text` - text in a layout box; font fields go in `layout`, `color` in `style`.
|
|
35
|
+
- `Image` - fetches/decodes/uploads an image: `src: string | Uint8Array`.
|
|
36
|
+
- `TextInput` - single-line input; `value`/`onInput`/`onSubmit`, controlled or
|
|
37
|
+
uncontrolled, plus `placeholder`, `maxLength`, `autoFocus`, `disabled`.
|
|
38
|
+
- `SafeArea` - pads children clear of system UI (notches, status bars); top and
|
|
39
|
+
bottom on by default, pass `false`/a number per edge.
|
|
40
|
+
- `theme` / `setTheme` - shared appearance (colors, spacing, radii, font sizes);
|
|
41
|
+
call `setTheme({...})` to override defaults.
|
|
42
|
+
|
|
43
|
+
## Minimal app (verified to render)
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import { render } from "@solidrt/core"
|
|
47
|
+
import { Window, View, Text } from "@solidrt/components"
|
|
48
|
+
import { createSignal } from "@solidjs/signals"
|
|
49
|
+
|
|
50
|
+
function App() {
|
|
51
|
+
let [count, setCount] = createSignal(0)
|
|
52
|
+
return (
|
|
53
|
+
<Window title="App" style={{ backgroundColor: "#0b0f17" }}
|
|
54
|
+
layout={{ flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 24 }}>
|
|
55
|
+
<Text layout={{ fontSize: 48, fontWeight: 800 }} style={{ color: "#1f6feb" }}>
|
|
56
|
+
{count()}
|
|
57
|
+
</Text>
|
|
58
|
+
<View onPointerDown={() => setCount((c) => c + 1)}
|
|
59
|
+
layout={{ padding: 16 }} style={{ backgroundColor: "#1f6feb", borderRadius: 12 }}>
|
|
60
|
+
<Text style={{ color: "#ffffff" }}>increment</Text>
|
|
61
|
+
</View>
|
|
62
|
+
</Window>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
render(() => <App />)
|
|
67
|
+
```
|
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidrt/components",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Antoine van Wel",
|
|
6
6
|
"type": "module",
|
|
@@ -10,11 +10,10 @@
|
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"src/",
|
|
13
|
-
"
|
|
14
|
-
"LICENSE"
|
|
13
|
+
"AGENTS.md"
|
|
15
14
|
],
|
|
16
15
|
"peerDependencies": {
|
|
17
16
|
"@solidjs/signals": "2.0.0-beta.14",
|
|
18
|
-
"@solidrt/core": "0.0.
|
|
17
|
+
"@solidrt/core": "0.0.11"
|
|
19
18
|
}
|
|
20
19
|
}
|
package/src/image.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createSignal, onCleanup } from "@solidjs/signals"
|
|
1
|
+
import { createSignal, createEffect, onCleanup } from "@solidjs/signals"
|
|
2
2
|
import { decodeImage, createTexture } from "@solidrt/core/gpu"
|
|
3
3
|
import type { LayoutProps, PointerProps } from "@solidrt/core"
|
|
4
4
|
import type { StyleProps } from "./types"
|
|
@@ -12,22 +12,45 @@ export interface ImageProps extends PointerProps {
|
|
|
12
12
|
//TODO onLoad, onError
|
|
13
13
|
//TODO release texture in onCleanup
|
|
14
14
|
export function Image(props: ImageProps) {
|
|
15
|
-
let [res] = createSignal
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
let [res, setRes] = createSignal<{ id: number; width: number; height: number }>()
|
|
16
|
+
|
|
17
|
+
// Load (and decode) whenever src changes. A url is fetched; bytes are used
|
|
18
|
+
// directly. The async result is pushed into the signal so the texture shows
|
|
19
|
+
// once ready; a stale flag drops results from a superseded src.
|
|
20
|
+
createEffect(
|
|
21
|
+
() => props.src,
|
|
22
|
+
(source) => {
|
|
23
|
+
let stale = false
|
|
24
|
+
|
|
25
|
+
;(async () => {
|
|
26
|
+
let bytes: Uint8Array
|
|
27
|
+
if (typeof source === "string") {
|
|
28
|
+
let response = await fetch(source)
|
|
29
|
+
bytes = await response.bytes()
|
|
30
|
+
} else {
|
|
31
|
+
bytes = source
|
|
32
|
+
}
|
|
33
|
+
if (stale) return
|
|
34
|
+
let { data, width, height } = decodeImage(bytes)
|
|
35
|
+
let id = createTexture(data, width, height)
|
|
36
|
+
setRes({ id, width, height })
|
|
37
|
+
})()
|
|
38
|
+
|
|
39
|
+
return () => {
|
|
40
|
+
stale = true
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
)
|
|
27
44
|
|
|
28
45
|
let src = () => res()?.id
|
|
29
46
|
let hasBorder = () => (props.style?.borderWidth ?? 0) > 0
|
|
30
47
|
|
|
48
|
+
// A texture sizes from its own width/height (not the box around it), so the
|
|
49
|
+
// numeric layout dimensions are forwarded to it. Omitting height lets the
|
|
50
|
+
// texture follow the image's intrinsic aspect ratio.
|
|
51
|
+
let texW = () => (typeof props.layout?.width === "number" ? props.layout.width : undefined)
|
|
52
|
+
let texH = () => (typeof props.layout?.height === "number" ? props.layout.height : undefined)
|
|
53
|
+
|
|
31
54
|
onCleanup(() => {
|
|
32
55
|
//TODO release texture
|
|
33
56
|
})
|
|
@@ -35,6 +58,8 @@ export function Image(props: ImageProps) {
|
|
|
35
58
|
return (
|
|
36
59
|
<view
|
|
37
60
|
{...props.layout}
|
|
61
|
+
overflow={props.style?.borderRadius != null ? "hidden" : props.layout?.overflow}
|
|
62
|
+
clipRadius={props.style?.borderRadius}
|
|
38
63
|
x={props.style?.x}
|
|
39
64
|
y={props.style?.y}
|
|
40
65
|
scale={props.style?.scale}
|
|
@@ -53,9 +78,9 @@ export function Image(props: ImageProps) {
|
|
|
53
78
|
pointerEvents={props.pointerEvents}
|
|
54
79
|
>
|
|
55
80
|
{props.style?.backgroundColor != null ? (
|
|
56
|
-
<d-rect color={props.style
|
|
81
|
+
<d-rect color={props.style?.backgroundColor} radius={props.style?.borderRadius} />
|
|
57
82
|
) : null}
|
|
58
|
-
<texture src={src()} />
|
|
83
|
+
<texture src={src()} width={texW()} height={texH()} />
|
|
59
84
|
{hasBorder() ? (
|
|
60
85
|
<d-rect
|
|
61
86
|
drawStyle="stroke"
|