@wonderlandlabs-pixi-ux/box 1.2.6 → 1.2.8
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.STYLES.md +87 -78
- package/README.md +45 -260
- package/TODO.md +9 -0
- package/dist/BorderThickness.d.ts +11 -0
- package/dist/BorderThickness.js +57 -0
- package/dist/BoxPixi.stories.d.ts +9 -0
- package/dist/BoxPixi.stories.js +883 -0
- package/dist/BoxStore.d.ts +44 -0
- package/dist/BoxStore.js +258 -0
- package/dist/BoxStore.stories.d.ts +19 -0
- package/dist/BoxStore.stories.js +718 -0
- package/dist/ComputeAxis.d.ts +24 -0
- package/dist/ComputeAxis.js +214 -0
- package/dist/ComputeAxis.stories.d.ts +13 -0
- package/dist/ComputeAxis.stories.js +272 -0
- package/dist/InsetDigest.d.ts +12 -0
- package/dist/InsetDigest.js +84 -0
- package/dist/_deprecated/BoxTree.d.ts +123 -0
- package/dist/_deprecated/BoxTree.helpers.d.ts +4 -0
- package/dist/_deprecated/BoxTree.helpers.js +166 -0
- package/dist/_deprecated/BoxTree.js +789 -0
- package/dist/_deprecated/BoxUx.d.ts +50 -0
- package/dist/_deprecated/BoxUx.js +360 -0
- package/dist/_deprecated/BoxUxBase.d.ts +24 -0
- package/dist/_deprecated/BoxUxBase.js +86 -0
- package/dist/_deprecated/BoxUxContextMap.d.ts +3 -0
- package/dist/_deprecated/BoxUxContextMap.js +10 -0
- package/dist/_deprecated/boxTreeRenderers.d.ts +4 -0
- package/dist/_deprecated/boxTreeRenderers.js +97 -0
- package/dist/_deprecated/constants.d.ts +86 -0
- package/dist/_deprecated/constants.js +131 -0
- package/dist/_deprecated/constants.ux.d.ts +11 -0
- package/dist/_deprecated/constants.ux.js +11 -0
- package/dist/_deprecated/enumUtils.d.ts +1 -0
- package/dist/_deprecated/enumUtils.js +7 -0
- package/dist/_deprecated/index.d.ts +12 -0
- package/dist/_deprecated/index.js +11 -0
- package/dist/_deprecated/pathUtils.d.ts +5 -0
- package/dist/_deprecated/pathUtils.js +31 -0
- package/dist/_deprecated/pixiEnvironment.d.ts +1 -0
- package/dist/_deprecated/pixiEnvironment.js +9 -0
- package/dist/_deprecated/sizeUtils.d.ts +13 -0
- package/dist/_deprecated/sizeUtils.js +39 -0
- package/dist/_deprecated/types.boxtree.d.ts +937 -0
- package/dist/_deprecated/types.boxtree.js +110 -0
- package/dist/_deprecated/types.d.ts +161 -0
- package/dist/_deprecated/types.js +66 -0
- package/dist/_deprecated/types.ux.d.ts +20 -0
- package/dist/_deprecated/types.ux.js +1 -0
- package/dist/_deprecated/utils.ux.d.ts +13 -0
- package/dist/_deprecated/utils.ux.js +61 -0
- package/dist/boxPixiStoryStyles.json +250 -0
- package/dist/constants.d.ts +38 -81
- package/dist/constants.js +54 -126
- package/dist/helpers.d.ts +34 -0
- package/dist/helpers.js +295 -0
- package/dist/index.d.ts +10 -12
- package/dist/index.js +10 -11
- package/dist/storyStyles.d.ts +2 -0
- package/dist/storyStyles.js +5 -0
- package/dist/storyStyles.json +286 -0
- package/dist/styleHelpers.d.ts +11 -0
- package/dist/styleHelpers.js +158 -0
- package/dist/toPixi.d.ts +3 -0
- package/dist/toPixi.helpers.d.ts +24 -0
- package/dist/toPixi.helpers.js +258 -0
- package/dist/toPixi.js +315 -0
- package/dist/toPixi.killlist.helpers.d.ts +5 -0
- package/dist/toPixi.killlist.helpers.js +28 -0
- package/dist/toSVG.d.ts +11 -0
- package/dist/toSVG.js +172 -0
- package/dist/types.d.ts +679 -103
- package/dist/types.js +131 -56
- package/package.json +3 -1
- package/src/BoxPixi.stories.ts +1002 -0
- package/src/BoxStore.stories.ts +770 -0
- package/src/BoxStore.ts +303 -0
- package/src/ComputeAxis.ts +312 -0
- package/src/InsetDigest.ts +110 -0
- package/src/_deprecated/BoxTree.helpers.ts +216 -0
- package/src/{BoxTree.ts → _deprecated/BoxTree.ts} +201 -278
- package/src/_deprecated/ComputeAxis.story-archive.ts +20 -0
- package/src/{boxTreeRenderers.ts → _deprecated/boxTreeRenderers.ts} +2 -47
- package/src/_deprecated/constants.ts +153 -0
- package/src/_deprecated/index.ts +153 -0
- package/src/{sizeUtils.ts → _deprecated/sizeUtils.ts} +9 -1
- package/src/_deprecated/types.ts +138 -0
- package/src/boxPixiStoryStyles.json +250 -0
- package/src/constants.ts +58 -141
- package/src/helpers.ts +425 -0
- package/src/index.ts +10 -153
- package/src/storyStyles.json +286 -0
- package/src/storyStyles.ts +7 -0
- package/src/styleHelpers.ts +211 -0
- package/src/toPixi.helpers.ts +372 -0
- package/src/toPixi.killlist.helpers.ts +41 -0
- package/src/toPixi.ts +473 -0
- package/src/toSVG.ts +236 -0
- package/src/types.ts +282 -70
- package/src/uuid.d.ts +3 -0
- package/test/BorderThickness.test.ts +46 -0
- package/test/BoxStore.test.ts +175 -0
- package/test/ComputeAxis.test.ts +282 -0
- package/test/gradient.test.ts +67 -0
- package/test/helpers.test.ts +212 -0
- package/test/styleHelpers.test.ts +33 -0
- package/test/toSVG.test.ts +134 -0
- package/test.zip +0 -0
- package/tsconfig.json +2 -1
- /package/src/{BoxUx.ts → _deprecated/BoxUx.ts} +0 -0
- /package/src/{BoxUxBase.ts → _deprecated/BoxUxBase.ts} +0 -0
- /package/src/{BoxUxContextMap.ts → _deprecated/BoxUxContextMap.ts} +0 -0
- /package/src/{constants.ux.ts → _deprecated/constants.ux.ts} +0 -0
- /package/src/{enumUtils.ts → _deprecated/enumUtils.ts} +0 -0
- /package/src/{pathUtils.ts → _deprecated/pathUtils.ts} +0 -0
- /package/src/{pixiEnvironment.ts → _deprecated/pixiEnvironment.ts} +0 -0
- /package/src/{types.boxtree.ts → _deprecated/types.boxtree.ts} +0 -0
- /package/src/{types.ux.ts → _deprecated/types.ux.ts} +0 -0
- /package/src/{utils.ux.ts → _deprecated/utils.ux.ts} +0 -0
package/README.STYLES.md
CHANGED
|
@@ -1,115 +1,124 @@
|
|
|
1
|
-
# Box Styles
|
|
1
|
+
# Box Styles
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The rebuilt `box` package does not ship a default renderer.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Instead, [`BoxStore`](/Users/bingomanatee/Documents/repos/wonderlandlabs-pixi-ux/packages/box/src/BoxStore.ts) provides a small style-resolution surface that renderers can use after layout has been computed.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
2. `root.assignUx((box) => new BoxUxPixi(box))`
|
|
9
|
-
3. `root.render()`
|
|
7
|
+
## Current Contract
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
A box cell can carry:
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
- `name`
|
|
12
|
+
- `variant`
|
|
13
|
+
- `states`
|
|
14
|
+
- `content`
|
|
15
|
+
- `children`
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
- `modeVerb[]`
|
|
17
|
-
- root-level `globalVerb[]`
|
|
17
|
+
`BoxStore` contributes:
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
- `styles`
|
|
20
|
+
- `styleStates`
|
|
21
|
+
- `styleNouns`
|
|
22
|
+
- `variant`
|
|
23
|
+
- `resolveStyle(propertyPath, { states?, extraNouns? })`
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
2. Try hierarchical object, e.g. `button.icon` then pick `bgColor`
|
|
23
|
-
3. Fallback to atomic path + property, e.g. `icon.bgColor`
|
|
24
|
-
4. Fallback to atomic object, e.g. `icon` then pick `bgColor`
|
|
25
|
+
The intent is:
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
- cells define nouns and state
|
|
28
|
+
- parents compute layout
|
|
29
|
+
- renderers ask the store for appearance
|
|
27
30
|
|
|
28
|
-
|
|
31
|
+
## Style Resolution
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
`resolveStyle()` builds noun paths from the current box node.
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
For a box named `button` with:
|
|
33
36
|
|
|
34
|
-
- `
|
|
35
|
-
- `
|
|
36
|
-
- `bgStrokeColor`
|
|
37
|
-
- `bgStrokeAlpha`
|
|
38
|
-
- `bgStrokeSize`
|
|
37
|
+
- `variant: 'primary'`
|
|
38
|
+
- `states: ['hover']`
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
and a renderer request of:
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
```ts
|
|
43
|
+
box.resolveStyle(['fill', 'color']);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
the store will try, in order:
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
1. `button.primary.fill.color` with `['hover']`
|
|
49
|
+
2. `button.fill.color` with `['hover']`
|
|
50
|
+
3. `color` with `['hover']`
|
|
47
51
|
|
|
48
|
-
`
|
|
52
|
+
If `extraNouns` are provided, they are inserted between the box noun path and the property path. That is how higher-level components can express mode-specific branches such as:
|
|
49
53
|
|
|
50
|
-
- `
|
|
51
|
-
- `
|
|
52
|
-
- `getContainer(key): unknown` with keys:
|
|
53
|
-
- `ROOT_CONTAINER`, `BACKGROUND_CONTAINER`, `CHILD_CONTAINER`, `CONTENT_CONTAINER`, `OVERLAY_CONTAINER`, `STROKE_CONTAINER`
|
|
54
|
-
- `attach(targetContainer?)` to mount root container to a parent (or `ux.app?.stage`)
|
|
55
|
-
- `generateStyleMap(box)` -> `{ fill: { color, alpha }, stroke: { color, alpha, width } }`
|
|
54
|
+
- `button.inline.fill.color`
|
|
55
|
+
- `button.icon.vertical.icon.size.x`
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
## Expected Style Manager Shape
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
- `BOX_RENDER_CONTENT_ORDER.CHILDREN = 50`
|
|
61
|
-
- `BOX_RENDER_CONTENT_ORDER.CONTENT = 75`
|
|
62
|
-
- `BOX_RENDER_CONTENT_ORDER.OVERLAY = 100`
|
|
63
|
-
- `BOX_UX_ORDER` map + `setUxOrder(name, zIndex)` + `getUxOrder(name)` for named custom layers
|
|
59
|
+
The style object attached to `box.styles` only needs to satisfy:
|
|
64
60
|
|
|
65
|
-
|
|
61
|
+
```ts
|
|
62
|
+
type BoxStyleQueryLike = {
|
|
63
|
+
nouns: string[];
|
|
64
|
+
states: string[];
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
type BoxStyleManagerLike = {
|
|
68
|
+
match: (query: BoxStyleQueryLike) => unknown;
|
|
69
|
+
matchHierarchy?: (query: BoxStyleQueryLike) => unknown;
|
|
70
|
+
};
|
|
71
|
+
```
|
|
66
72
|
|
|
67
|
-
|
|
68
|
-
2. Child UX instances are updated
|
|
69
|
-
3. Child container is cleared and rebuilt from current child UX containers
|
|
70
|
-
4. Optional `box.content` is rendered into the `CONTENT` layer (`text` and image URL content)
|
|
71
|
-
5. Background/stroke are redrawn from styles
|
|
72
|
-
6. `content` is sorted by `zIndex` and non-empty items are attached to the root container
|
|
73
|
+
[`@wonderlandlabs-pixi-ux/style-tree`](https://www.npmjs.com/package/@wonderlandlabs-pixi-ux/style-tree) already matches that shape and is the intended default pairing.
|
|
73
74
|
|
|
74
|
-
|
|
75
|
+
## Renderer Pattern
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
to reuse lifecycle patterns (`init`/`render`/`clear` and visible up/down flow).
|
|
77
|
+
The happy-path renderer flow is:
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
1. Build or mutate the `BoxStore` tree.
|
|
80
|
+
2. Attach `styles` to the root store.
|
|
81
|
+
3. Call `box.update()` to compute locations.
|
|
82
|
+
4. Walk the resulting tree and render from `location`, `content`, and resolved styles.
|
|
80
83
|
|
|
81
|
-
|
|
82
|
-
- `Graphics`
|
|
83
|
-
- draws fill from `bgColor`
|
|
84
|
-
- `CHILDREN`:
|
|
85
|
-
- `Container`
|
|
86
|
-
- receives child renderer containers each frame
|
|
87
|
-
- `CONTENT`:
|
|
88
|
-
- `Container`
|
|
89
|
-
- receives optional `box.content` rendering (`text` and image URL content)
|
|
90
|
-
- `OVERLAY`:
|
|
91
|
-
- `Container`
|
|
92
|
-
- contains stroke `Graphics` drawing from `bgStrokeColor` + `bgStrokeSize`
|
|
84
|
+
That keeps the responsibilities separated:
|
|
93
85
|
|
|
94
|
-
|
|
86
|
+
- `ComputeAxis` resolves spans and alignment
|
|
87
|
+
- `BoxStore` owns the layout tree and style lookup context
|
|
88
|
+
- your renderer owns Pixi, HTML, SVG, canvas, or any other output target
|
|
95
89
|
|
|
96
|
-
|
|
90
|
+
## Example
|
|
97
91
|
|
|
98
92
|
```ts
|
|
99
|
-
import {
|
|
100
|
-
import {
|
|
93
|
+
import { BoxStore } from '@wonderlandlabs-pixi-ux/box';
|
|
94
|
+
import { fromJSON } from '@wonderlandlabs-pixi-ux/style-tree';
|
|
95
|
+
|
|
96
|
+
const styles = fromJSON({
|
|
97
|
+
button: {
|
|
98
|
+
fill: {
|
|
99
|
+
$*: { color: { r: 0.2, g: 0.4, b: 0.8 }, alpha: 1 }
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const box = new BoxStore({
|
|
105
|
+
value: {
|
|
106
|
+
name: 'button',
|
|
107
|
+
absolute: true,
|
|
108
|
+
dim: { x: 0, y: 0, w: 120, h: 40 },
|
|
109
|
+
align: { direction: 'horizontal', xPosition: 'center', yPosition: 'center' },
|
|
110
|
+
children: [],
|
|
111
|
+
},
|
|
112
|
+
});
|
|
101
113
|
|
|
102
114
|
box.styles = styles;
|
|
103
|
-
|
|
104
|
-
const custom = new Graphics();
|
|
105
|
-
custom.visible = true;
|
|
115
|
+
box.update();
|
|
106
116
|
|
|
107
|
-
|
|
108
|
-
ux.content.set('CUSTOM', custom);
|
|
109
|
-
ux.box.render();
|
|
117
|
+
const fillColor = box.resolveStyle(['fill', 'color']);
|
|
110
118
|
```
|
|
111
119
|
|
|
112
120
|
## Notes
|
|
113
121
|
|
|
114
|
-
- The
|
|
115
|
-
-
|
|
122
|
+
- The old `BoxTree` / `BoxUxPixi` renderer stack still exists under [`src/_deprecated`](/Users/bingomanatee/Documents/repos/wonderlandlabs-pixi-ux/packages/box/src/_deprecated), but it is legacy code now.
|
|
123
|
+
- The new architecture is intentionally renderer-agnostic.
|
|
124
|
+
- `content` is descriptive data, not a renderer by itself.
|
package/README.md
CHANGED
|
@@ -1,284 +1,69 @@
|
|
|
1
1
|
# @wonderlandlabs-pixi-ux/box
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
This emulates FlexBox based layout. This module is a data-model of a flex layout system.
|
|
5
|
-
It was designed for Pixi; however, as an abstract DSL for visual trees it may have other uses.
|
|
3
|
+
`box` is a small parent-driven layout model for rectangular children.
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
The current implementation is centered around:
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
```
|
|
7
|
+
- [`BoxStore`](/Users/bingomanatee/Documents/repos/wonderlandlabs-pixi-ux/packages/box/src/BoxStore.ts)
|
|
8
|
+
- [`ComputeAxis`](/Users/bingomanatee/Documents/repos/wonderlandlabs-pixi-ux/packages/box/src/ComputeAxis.ts)
|
|
12
9
|
|
|
13
|
-
##
|
|
10
|
+
## Current Model
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
} from '@wonderlandlabs-pixi-ux/box';
|
|
12
|
+
- The parent owns alignment.
|
|
13
|
+
- Children provide dimensions.
|
|
14
|
+
- Child `x` / `y` are not part of the happy-path alignment flow.
|
|
15
|
+
- Width and height are computed from the parent container.
|
|
16
|
+
- All units are relative to the parent in the dimension they address.
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
id: 'root',
|
|
24
|
-
styleName: 'button',
|
|
25
|
-
globalVerb: [],
|
|
26
|
-
area: {
|
|
27
|
-
x: 60,
|
|
28
|
-
y: 50,
|
|
29
|
-
width: { mode: UNIT_BASIS.PX, value: 720 },
|
|
30
|
-
height: { mode: UNIT_BASIS.PX, value: 340 },
|
|
31
|
-
px: 's',
|
|
32
|
-
py: 's',
|
|
33
|
-
},
|
|
34
|
-
align: {
|
|
35
|
-
x: ALIGN.START,
|
|
36
|
-
y: ALIGN.START,
|
|
37
|
-
direction: 'column',
|
|
38
|
-
},
|
|
39
|
-
children: {
|
|
40
|
-
header: {
|
|
41
|
-
styleName: 'header',
|
|
42
|
-
area: {
|
|
43
|
-
x: 0,
|
|
44
|
-
y: 0,
|
|
45
|
-
width: { mode: UNIT_BASIS.PERCENT, value: 1 },
|
|
46
|
-
height: { mode: UNIT_BASIS.PX, value: 60 },
|
|
47
|
-
px: 's',
|
|
48
|
-
py: 's',
|
|
49
|
-
},
|
|
50
|
-
align: { x: 's', y: 's', direction: 'row' },
|
|
51
|
-
},
|
|
52
|
-
icon: {
|
|
53
|
-
styleName: 'icon',
|
|
54
|
-
modeVerb: ['hover'],
|
|
55
|
-
area: {
|
|
56
|
-
x: 0,
|
|
57
|
-
y: 0,
|
|
58
|
-
width: { mode: UNIT_BASIS.PX, value: 24 },
|
|
59
|
-
height: { mode: UNIT_BASIS.PX, value: 24 },
|
|
60
|
-
px: 's',
|
|
61
|
-
py: 's',
|
|
62
|
-
},
|
|
63
|
-
align: { x: 's', y: 's', direction: 'column' },
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
});
|
|
18
|
+
That means:
|
|
67
19
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
20
|
+
- width-like values resolve against the parent width
|
|
21
|
+
- height-like values resolve against the parent height
|
|
22
|
+
- percent values are always percentages of the parent dimension
|
|
23
|
+
- absolute pixel values are still interpreted within the parent container
|
|
72
24
|
|
|
73
|
-
##
|
|
25
|
+
## Flow
|
|
74
26
|
|
|
75
|
-
|
|
27
|
+
The current layout pass is:
|
|
76
28
|
|
|
77
|
-
|
|
78
|
-
|
|
29
|
+
1. Resolve the main-axis spans for the children.
|
|
30
|
+
2. Complete unresolved fractional spans.
|
|
31
|
+
3. Place children from the parent alignment and the resolved spans.
|
|
32
|
+
4. Recurse into child boxes using the computed location rectangles.
|
|
79
33
|
|
|
80
|
-
|
|
81
|
-
layout.assignUx((box) => new BoxUxPixi(box));
|
|
82
|
-
layout.render(); // calls ux.init() once, then ux.render()
|
|
83
|
-
```
|
|
34
|
+
`ComputeAxis` currently handles:
|
|
84
35
|
|
|
85
|
-
|
|
36
|
+
- absolute pixel dimensions
|
|
37
|
+
- percentage dimensions
|
|
38
|
+
- fractional dimensions on the main axis by weighted remainder distribution
|
|
39
|
+
- fractional dimensions on the cross axis by resolving to the largest resolved peer span
|
|
40
|
+
- cross-axis `fill`
|
|
41
|
+
- parent-owned start / center / end alignment
|
|
86
42
|
|
|
87
|
-
|
|
43
|
+
## Styles
|
|
88
44
|
|
|
89
|
-
|
|
90
|
-
const layout = new BoxTree({
|
|
91
|
-
id: 'root',
|
|
92
|
-
area: { x: 0, y: 0, width: 200, height: 100 },
|
|
93
|
-
ux: (box) => new BoxUxPixi(box),
|
|
94
|
-
});
|
|
95
|
-
layout.styles = styles;
|
|
96
|
-
```
|
|
45
|
+
`BoxStore` also exposes style context for renderers:
|
|
97
46
|
|
|
98
|
-
|
|
47
|
+
- `styles`
|
|
48
|
+
- `variant`
|
|
49
|
+
- `styleStates`
|
|
50
|
+
- `styleNouns`
|
|
51
|
+
- `resolveStyle(...)`
|
|
99
52
|
|
|
100
|
-
`
|
|
53
|
+
See [`README.STYLES.md`](/Users/bingomanatee/Documents/repos/wonderlandlabs-pixi-ux/packages/box/README.STYLES.md) for the renderer-facing contract.
|
|
101
54
|
|
|
102
|
-
|
|
103
|
-
- `modeVerb` is node-local state (`hover`, `selected`, ...)
|
|
104
|
-
- `globalVerb` is root-level state shared by all descendants (`disabled`, ...)
|
|
55
|
+
## Status
|
|
105
56
|
|
|
106
|
-
|
|
57
|
+
This package is mid-refactor.
|
|
107
58
|
|
|
108
|
-
|
|
109
|
-
|
|
59
|
+
The active architecture is the simplified `BoxStore` / `ComputeAxis` path in `src/`.
|
|
60
|
+
Older `BoxTree`-style code still exists under [`src/_deprecated`](/Users/bingomanatee/Documents/repos/wonderlandlabs-pixi-ux/packages/box/src/_deprecated), but it is not the current direction.
|
|
110
61
|
|
|
111
|
-
|
|
62
|
+
## Test Artifacts
|
|
112
63
|
|
|
113
|
-
|
|
64
|
+
The `ComputeAxis` tests generate:
|
|
114
65
|
|
|
115
|
-
|
|
116
|
-
|
|
66
|
+
- SVG diagrams for layout inspection
|
|
67
|
+
- HTML tables for readable scenario metadata
|
|
117
68
|
|
|
118
|
-
|
|
119
|
-
button: {
|
|
120
|
-
icon: {
|
|
121
|
-
fill: {
|
|
122
|
-
$*: { color: { r: 0.2, g: 0.2, b: 0.2 }, alpha: 1 },
|
|
123
|
-
$disabled: { color: { r: 0.45, g: 0.45, b: 0.45 }, alpha: 1 },
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
icon: {
|
|
128
|
-
fill: {
|
|
129
|
-
$*: { color: { r: 1, g: 1, b: 1 }, alpha: 1 },
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
const icon = layout.getChild('icon');
|
|
135
|
-
const fillStyle = icon?.resolveStyle(styles, ['pressed']);
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## Default Ux
|
|
139
|
-
|
|
140
|
-
`box` ships with `BoxUxPixi`, a default Pixi UX implementation for `BoxTree`.
|
|
141
|
-
|
|
142
|
-
Behavior:
|
|
143
|
-
|
|
144
|
-
- Creates a container when `container` is not provided
|
|
145
|
-
- Uses public `content: MapEnhanced` (a `Map<string, unknown>` subclass)
|
|
146
|
-
- `content.$box` points at the owning `BoxTree`
|
|
147
|
-
- Exposes `ux.getContainer(key): unknown` for renderer-to-renderer handoff:
|
|
148
|
-
- `ROOT_CONTAINER`, `BACKGROUND_CONTAINER`, `CHILD_CONTAINER`, `CONTENT_CONTAINER`, `OVERLAY_CONTAINER`, `STROKE_CONTAINER`
|
|
149
|
-
- Exposes `ux.attach(targetContainer?)`:
|
|
150
|
-
- attaches root container to `targetContainer`
|
|
151
|
-
- if omitted, uses `ux.app?.stage`
|
|
152
|
-
- Pre-populates built-in layers if absent:
|
|
153
|
-
- `BOX_RENDER_CONTENT_ORDER.BACKGROUND = 0`
|
|
154
|
-
- `BOX_RENDER_CONTENT_ORDER.CHILDREN = 50`
|
|
155
|
-
- `BOX_RENDER_CONTENT_ORDER.CONTENT = 75`
|
|
156
|
-
- `BOX_RENDER_CONTENT_ORDER.OVERLAY = 100`
|
|
157
|
-
- Supports named layer order lookups:
|
|
158
|
-
- `BOX_UX_ORDER` (`ReadonlyMap<string, number>`)
|
|
159
|
-
- `setUxOrder(name, zIndex)` with duplicate z-index protection
|
|
160
|
-
- `getUxOrder(name)` for safe lookup
|
|
161
|
-
- Rebuilds children layer each render by clearing and re-adding child UX containers
|
|
162
|
-
- Draws a background graphic from style props:
|
|
163
|
-
- `[stylePath].bgColor`
|
|
164
|
-
- `[stylePath].bgAlpha`
|
|
165
|
-
- `[stylePath].bgStrokeColor`
|
|
166
|
-
- `[stylePath].bgStrokeAlpha`
|
|
167
|
-
- `[stylePath].bgStrokeSize`
|
|
168
|
-
- Exposes `ux.generateStyleMap(box)` with normalized shape:
|
|
169
|
-
- `fill: { color, alpha }`
|
|
170
|
-
- `stroke: { color, alpha, width }`
|
|
171
|
-
- Honors `box.isVisible`:
|
|
172
|
-
- when `false`, detaches (hides) the container without destroying render content
|
|
173
|
-
- when `true` again, existing layers are reused on next render
|
|
174
|
-
- Iterates `content` and injects non-empty items into root container sorted by each item's `zIndex`
|
|
175
|
-
|
|
176
|
-
```ts
|
|
177
|
-
import { Graphics } from 'pixi.js';
|
|
178
|
-
import {
|
|
179
|
-
BOX_RENDER_CONTENT_ORDER,
|
|
180
|
-
BoxTree,
|
|
181
|
-
BoxUxPixi,
|
|
182
|
-
} from '@wonderlandlabs-pixi-ux/box';
|
|
183
|
-
import { fromJSON } from '@wonderlandlabs-pixi-ux/style-tree';
|
|
184
|
-
|
|
185
|
-
const styles = fromJSON({
|
|
186
|
-
button: {
|
|
187
|
-
bgColor: { $*: 0x2d3a45 },
|
|
188
|
-
bgStrokeColor: { $*: 0x8fd3ff },
|
|
189
|
-
bgStrokeSize: { $*: 2 },
|
|
190
|
-
icon: {
|
|
191
|
-
bgColor: { $*: 0x3a4957 },
|
|
192
|
-
},
|
|
193
|
-
},
|
|
194
|
-
icon: {
|
|
195
|
-
bgColor: { $*: 0x222222 },
|
|
196
|
-
},
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
const root = new BoxTree({
|
|
200
|
-
id: 'root',
|
|
201
|
-
styleName: 'button',
|
|
202
|
-
area: { x: 40, y: 30, width: 200, height: 100 },
|
|
203
|
-
children: {
|
|
204
|
-
icon: {
|
|
205
|
-
styleName: 'icon',
|
|
206
|
-
order: 0,
|
|
207
|
-
area: { width: 24, height: 24 },
|
|
208
|
-
},
|
|
209
|
-
},
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
root.styles = styles;
|
|
213
|
-
const ux = new BoxUxPixi(root);
|
|
214
|
-
root.render();
|
|
215
|
-
// manual mount
|
|
216
|
-
ux.attach(app.stage);
|
|
217
|
-
|
|
218
|
-
// custom content layer example:
|
|
219
|
-
const custom = new Graphics();
|
|
220
|
-
custom.zIndex = 76;
|
|
221
|
-
custom.visible = true;
|
|
222
|
-
ux.content.set('CUSTOM', custom);
|
|
223
|
-
ux.content.get('OVERLAY')?.visible = true;
|
|
224
|
-
const ownerBox = ux.content.$box;
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
## Override Points
|
|
228
|
-
|
|
229
|
-
`BoxUxBase` is the renderer-agnostic lifecycle base (`init`, `render`, `clear`, visible up/down flow).
|
|
230
|
-
`BoxUxPixi` extends `BoxUxBase` and provides the Pixi-specific containers/graphics behavior.
|
|
231
|
-
|
|
232
|
-
For custom behavior, return your own UX instance from `assignUx((box) => ...)`, either:
|
|
233
|
-
|
|
234
|
-
- extending `BoxUxBase` for a new renderer, or
|
|
235
|
-
- extending `BoxUxPixi` for Pixi-specific customization.
|
|
236
|
-
|
|
237
|
-
Detailed style/composition docs:
|
|
238
|
-
|
|
239
|
-
- [`README.STYLES.md`](./README.STYLES.md)
|
|
240
|
-
|
|
241
|
-
## Optional Pixi Debug Rendering
|
|
242
|
-
|
|
243
|
-
If you just want geometry previews, you can use `boxTreeToPixi`:
|
|
244
|
-
|
|
245
|
-
```ts
|
|
246
|
-
import { boxTreeToPixi } from '@wonderlandlabs-pixi-ux/box';
|
|
247
|
-
|
|
248
|
-
const graphics = await boxTreeToPixi(layout, {
|
|
249
|
-
includeRoot: true,
|
|
250
|
-
fill: 0x2d3a45,
|
|
251
|
-
fillAlpha: 0.35,
|
|
252
|
-
stroke: 0x8fd3ff,
|
|
253
|
-
strokeAlpha: 0.9,
|
|
254
|
-
strokeWidth: 2,
|
|
255
|
-
});
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
## Public API
|
|
259
|
-
|
|
260
|
-
- `BoxTree`
|
|
261
|
-
- `BoxUx` (UX object type)
|
|
262
|
-
- `BoxUxMapFn`
|
|
263
|
-
- `BoxRenderer` (legacy alias of `BoxUx`)
|
|
264
|
-
- `BoxRenderMapFn` (legacy alias of `BoxUxMapFn`)
|
|
265
|
-
- `MapEnhanced`
|
|
266
|
-
- `BoxUxBase`
|
|
267
|
-
- `BoxUxPixi`
|
|
268
|
-
- `BoxTreeRenderer` (legacy alias of `BoxUxPixi`)
|
|
269
|
-
- `BOX_UX_ORDER`, `getUxOrder`, `setUxOrder`
|
|
270
|
-
- `BOX_RENDER_CONTENT_ORDER`
|
|
271
|
-
- `createBoxTreeState`
|
|
272
|
-
- `resolveTreeMeasurement`
|
|
273
|
-
- `resolveMeasurementPx`
|
|
274
|
-
- `resolveConstraintValuePx`
|
|
275
|
-
- `applyAxisConstraints`
|
|
276
|
-
- `boxTreeToPixi`
|
|
277
|
-
- `boxTreeToSvg`
|
|
278
|
-
- `pathToString`, `pathString`, `combinePaths`
|
|
279
|
-
- `ALIGN`, `AXIS`, `UNIT_BASIS`, `SIZE_MODE`, `SIZE_MODE_INPUT`
|
|
280
|
-
- `TreeStyleNameSchema`, `TreeVerbSchema`, `TreeVerbListSchema`
|
|
281
|
-
|
|
282
|
-
## Data Model
|
|
283
|
-
|
|
284
|
-
Use exported BoxTree schemas/types in `src/types.boxtree.ts` and measurement schemas in `src/types.ts` as the source of truth.
|
|
69
|
+
These artifacts are written under [`packages/box/test/artifacts`](/Users/bingomanatee/Documents/repos/wonderlandlabs-pixi-ux/packages/box/test/artifacts) and are ignored by the package-level `.gitignore`.
|
package/TODO.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# TODO
|
|
2
|
+
|
|
3
|
+
- use Immer/diff to only recompute the children that have changed or the children of changed nodes.
|
|
4
|
+
- Decide how overflow should resolve when content exceeds the parent container:
|
|
5
|
+
squash content to fit, crop content to the container, or allow overflow without intervention.
|
|
6
|
+
- Consider adding min/max sizing constraints, especially if fractional sizing makes alignment too inert.
|
|
7
|
+
- Keep the parent-owned alignment model strict: children define dimensions, parents place them.
|
|
8
|
+
- Add a first-class renderer package or reference renderer examples for Pixi, HTML, and SVG.
|
|
9
|
+
- Normalize package-root exports so sibling packages do not need `dist` subpath imports during local compilation.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { BorderPartType, BoxBorderType } from './types.js';
|
|
2
|
+
export type BorderInsets = Record<BorderPartType, number>;
|
|
3
|
+
export declare class BorderThickness {
|
|
4
|
+
#private;
|
|
5
|
+
readonly top: number;
|
|
6
|
+
readonly right: number;
|
|
7
|
+
readonly bottom: number;
|
|
8
|
+
readonly left: number;
|
|
9
|
+
constructor(defs?: BoxBorderType);
|
|
10
|
+
toInsets(): BorderInsets;
|
|
11
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
+
};
|
|
6
|
+
var _a, _BorderThickness_apply;
|
|
7
|
+
import { BORDER_PART_BOTTOM, BORDER_PART_LEFT, BORDER_PART_RIGHT, BORDER_PART_TOP, BORDER_SCOPE_ALL, BORDER_SCOPE_BOTTOM, BORDER_SCOPE_HORIZ, BORDER_SCOPE_LEFT, BORDER_SCOPE_RIGHT, BORDER_SCOPE_TOP, BORDER_SCOPE_VERT, } from './constants.js';
|
|
8
|
+
export class BorderThickness {
|
|
9
|
+
constructor(defs = []) {
|
|
10
|
+
const insets = defs.reduce((nextInsets, def) => {
|
|
11
|
+
return __classPrivateFieldGet(_a, _a, "m", _BorderThickness_apply).call(_a, nextInsets, def);
|
|
12
|
+
}, {
|
|
13
|
+
[BORDER_PART_TOP]: 0,
|
|
14
|
+
[BORDER_PART_RIGHT]: 0,
|
|
15
|
+
[BORDER_PART_BOTTOM]: 0,
|
|
16
|
+
[BORDER_PART_LEFT]: 0,
|
|
17
|
+
});
|
|
18
|
+
this.top = insets[BORDER_PART_TOP];
|
|
19
|
+
this.right = insets[BORDER_PART_RIGHT];
|
|
20
|
+
this.bottom = insets[BORDER_PART_BOTTOM];
|
|
21
|
+
this.left = insets[BORDER_PART_LEFT];
|
|
22
|
+
}
|
|
23
|
+
toInsets() {
|
|
24
|
+
return {
|
|
25
|
+
[BORDER_PART_TOP]: this.top,
|
|
26
|
+
[BORDER_PART_RIGHT]: this.right,
|
|
27
|
+
[BORDER_PART_BOTTOM]: this.bottom,
|
|
28
|
+
[BORDER_PART_LEFT]: this.left,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
_a = BorderThickness, _BorderThickness_apply = function _BorderThickness_apply(insets, def) {
|
|
33
|
+
const { scope, value } = def;
|
|
34
|
+
switch (scope) {
|
|
35
|
+
case BORDER_SCOPE_ALL:
|
|
36
|
+
return {
|
|
37
|
+
[BORDER_PART_TOP]: value,
|
|
38
|
+
[BORDER_PART_RIGHT]: value,
|
|
39
|
+
[BORDER_PART_BOTTOM]: value,
|
|
40
|
+
[BORDER_PART_LEFT]: value,
|
|
41
|
+
};
|
|
42
|
+
case BORDER_SCOPE_HORIZ:
|
|
43
|
+
return { ...insets, [BORDER_PART_LEFT]: value, [BORDER_PART_RIGHT]: value };
|
|
44
|
+
case BORDER_SCOPE_VERT:
|
|
45
|
+
return { ...insets, [BORDER_PART_TOP]: value, [BORDER_PART_BOTTOM]: value };
|
|
46
|
+
case BORDER_SCOPE_TOP:
|
|
47
|
+
return { ...insets, [BORDER_PART_TOP]: value };
|
|
48
|
+
case BORDER_SCOPE_RIGHT:
|
|
49
|
+
return { ...insets, [BORDER_PART_RIGHT]: value };
|
|
50
|
+
case BORDER_SCOPE_BOTTOM:
|
|
51
|
+
return { ...insets, [BORDER_PART_BOTTOM]: value };
|
|
52
|
+
case BORDER_SCOPE_LEFT:
|
|
53
|
+
return { ...insets, [BORDER_PART_LEFT]: value };
|
|
54
|
+
default:
|
|
55
|
+
return insets;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/html';
|
|
2
|
+
type Story = StoryObj;
|
|
3
|
+
declare const meta: Meta;
|
|
4
|
+
export default meta;
|
|
5
|
+
export declare const PixiBoxRendererPOC: Story;
|
|
6
|
+
export declare const ProductCatalogGrid: Story;
|
|
7
|
+
export declare const ProductDetailHero: Story;
|
|
8
|
+
export declare const ProductComparisonStrip: Story;
|
|
9
|
+
export declare const BoxDebugLoop: Story;
|