@adia-ai/web-components 0.7.9 → 0.7.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/CHANGELOG.md +33 -0
- package/components/button/button.css +43 -16
- package/components/frame/frame.a2ui.json +85 -0
- package/components/frame/frame.class.js +31 -0
- package/components/frame/frame.css +42 -0
- package/components/frame/frame.d.ts +32 -0
- package/components/frame/frame.js +17 -0
- package/components/frame/frame.yaml +86 -0
- package/components/index.js +1 -0
- package/components/list/list.css +15 -8
- package/components/preview/preview.class.js +9 -0
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +81 -81
- package/package.json +1 -1
- package/styles/components.css +1 -0
- package/styles/verse.css +5 -5
- package/traits/resizable/resizable.js +49 -36
- package/traits/resizable/resizable.test.js +19 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/web-components",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.11",
|
|
4
4
|
"description": "AdiaUI web components \u2014 vanilla custom elements. A2UI runtime (renderer, registry, streams, wiring) lives in @adia-ai/a2ui-runtime.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./index.d.ts",
|
package/styles/components.css
CHANGED
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
@import "../components/timeline/timeline.css";
|
|
48
48
|
@import "../components/upload/upload.css";
|
|
49
49
|
@import "../components/card/card.css";
|
|
50
|
+
@import "../components/frame/frame.css";
|
|
50
51
|
@import "../components/avatar/avatar.css";
|
|
51
52
|
@import "../components/progress/progress.css";
|
|
52
53
|
@import "../components/skeleton/skeleton.css";
|
package/styles/verse.css
CHANGED
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
/* ── Radius — verse register: tighter bounds (max 16px). Re-declares the
|
|
51
51
|
clamps so they resolve verse's min/max (base clamps compute at :root). ── */
|
|
52
52
|
--a-radius-min: 0.25rem; /* 4px */
|
|
53
|
-
--a-radius-max:
|
|
53
|
+
--a-radius-max: 0.75rem; /* 12px */
|
|
54
54
|
--a-radius-xs: clamp(var(--a-radius-min), calc(var(--a-radius-k) * var(--a-radius-max) * var(--a-radius-xs-k)), var(--a-radius-max));
|
|
55
55
|
--a-radius-sm: clamp(var(--a-radius-min), calc(var(--a-radius-k) * var(--a-radius-max) * var(--a-radius-sm-k)), var(--a-radius-max));
|
|
56
56
|
--a-radius-md: clamp(var(--a-radius-min), calc(var(--a-radius-k) * var(--a-radius-max) * var(--a-radius-md-k)), var(--a-radius-max));
|
|
@@ -109,10 +109,10 @@
|
|
|
109
109
|
roles → -sm, text/data roles → -md. The global [size] rules override these
|
|
110
110
|
on [size]-bearing elements (resolving verse's sm/lg token values). */
|
|
111
111
|
[verse]:not([size]) {
|
|
112
|
-
--a-display-size: var(--a-display-
|
|
113
|
-
--a-title-size: var(--a-title-
|
|
114
|
-
--a-heading-size: var(--a-heading-
|
|
115
|
-
--a-section-size: var(--a-section-
|
|
112
|
+
--a-display-size: var(--a-display-md);
|
|
113
|
+
--a-title-size: var(--a-title-md);
|
|
114
|
+
--a-heading-size: var(--a-heading-md);
|
|
115
|
+
--a-section-size: var(--a-section-md);
|
|
116
116
|
--a-subsection-size: var(--a-subsection-md);
|
|
117
117
|
--a-body-size: var(--a-body-md);
|
|
118
118
|
--a-deck-size: var(--a-deck-md);
|
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
import { defineTrait } from '../define.js';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
3
|
+
const EDGE = 8; // edge hit-zone thickness
|
|
4
|
+
const CORNER = 14; // corner hit-zone (square, sits on top of the edges it overlaps)
|
|
5
|
+
|
|
6
|
+
// Edges resize one axis; corners resize both (x/y at once). `dw`/`dh` are the sign
|
|
7
|
+
// applied to the pointer delta (dx/dy): +1 grows from this side, -1 grows from the
|
|
8
|
+
// opposite (anchored) side, 0 leaves that axis untouched. Corners are listed LAST so
|
|
9
|
+
// they're appended after the edges and win the hit-test where they overlap.
|
|
10
|
+
const HANDLES = [
|
|
11
|
+
{ name: 'top', dw: 0, dh: -1, cursor: 'ns-resize', geo: { top: '0', left: '0', right: '0', height: `${EDGE}px` } },
|
|
12
|
+
{ name: 'right', dw: 1, dh: 0, cursor: 'ew-resize', geo: { top: '0', right: '0', bottom: '0', width: `${EDGE}px` } },
|
|
13
|
+
{ name: 'bottom', dw: 0, dh: 1, cursor: 'ns-resize', geo: { bottom: '0', left: '0', right: '0', height: `${EDGE}px` } },
|
|
14
|
+
{ name: 'left', dw: -1, dh: 0, cursor: 'ew-resize', geo: { top: '0', left: '0', bottom: '0', width: `${EDGE}px` } },
|
|
15
|
+
{ name: 'top-left', dw: -1, dh: -1, cursor: 'nwse-resize', geo: { top: '0', left: '0', width: `${CORNER}px`, height: `${CORNER}px` } },
|
|
16
|
+
{ name: 'top-right', dw: 1, dh: -1, cursor: 'nesw-resize', geo: { top: '0', right: '0', width: `${CORNER}px`, height: `${CORNER}px` } },
|
|
17
|
+
{ name: 'bottom-right', dw: 1, dh: 1, cursor: 'nwse-resize', geo: { bottom: '0', right: '0', width: `${CORNER}px`, height: `${CORNER}px` } },
|
|
18
|
+
{ name: 'bottom-left', dw: -1, dh: 1, cursor: 'nesw-resize', geo: { bottom: '0', left: '0', width: `${CORNER}px`, height: `${CORNER}px` } },
|
|
19
|
+
];
|
|
5
20
|
|
|
6
21
|
export const resizable = defineTrait({
|
|
7
22
|
name: 'resizable',
|
|
@@ -12,70 +27,68 @@ export const resizable = defineTrait({
|
|
|
12
27
|
config: [],
|
|
13
28
|
setup({ host }) {
|
|
14
29
|
let resizing = false;
|
|
15
|
-
let
|
|
30
|
+
let active = null;
|
|
16
31
|
let startX = 0;
|
|
17
32
|
let startY = 0;
|
|
18
33
|
let startWidth = 0;
|
|
19
34
|
let startHeight = 0;
|
|
20
|
-
let
|
|
21
|
-
let
|
|
35
|
+
let centerX = 0;
|
|
36
|
+
let centerY = 0;
|
|
37
|
+
let symmetric = false;
|
|
22
38
|
const handles = [];
|
|
23
39
|
|
|
24
|
-
// Ensure host is positioned
|
|
25
|
-
|
|
26
|
-
if (pos === 'static') {
|
|
40
|
+
// Ensure host is positioned so the absolute hit-zones anchor to it.
|
|
41
|
+
if (getComputedStyle(host).position === 'static') {
|
|
27
42
|
host.style.position = 'relative';
|
|
28
43
|
}
|
|
29
44
|
|
|
30
|
-
for (const
|
|
45
|
+
for (const h of HANDLES) {
|
|
31
46
|
const handle = document.createElement('div');
|
|
32
|
-
handle.dataset.resizableHandle =
|
|
33
|
-
Object.assign(handle.style, {
|
|
34
|
-
position: 'absolute',
|
|
35
|
-
zIndex: '9999',
|
|
36
|
-
...(edge === 'top' && { top: '0', left: '0', right: '0', height: `${EDGE_SIZE}px`, cursor: 'ns-resize' }),
|
|
37
|
-
...(edge === 'bottom' && { bottom: '0', left: '0', right: '0', height: `${EDGE_SIZE}px`, cursor: 'ns-resize' }),
|
|
38
|
-
...(edge === 'left' && { top: '0', bottom: '0', left: '0', width: `${EDGE_SIZE}px`, cursor: 'ew-resize' }),
|
|
39
|
-
...(edge === 'right' && { top: '0', bottom: '0', right: '0', width: `${EDGE_SIZE}px`, cursor: 'ew-resize' }),
|
|
40
|
-
});
|
|
47
|
+
handle.dataset.resizableHandle = h.name;
|
|
48
|
+
Object.assign(handle.style, { position: 'absolute', zIndex: '9999', cursor: h.cursor, ...h.geo });
|
|
41
49
|
|
|
42
50
|
handle.addEventListener('pointerdown', (e) => {
|
|
43
51
|
e.stopPropagation();
|
|
44
52
|
resizing = true;
|
|
45
|
-
|
|
53
|
+
active = h.name;
|
|
46
54
|
startX = e.clientX;
|
|
47
55
|
startY = e.clientY;
|
|
48
56
|
const rect = host.getBoundingClientRect();
|
|
49
57
|
startWidth = rect.width;
|
|
50
58
|
startHeight = rect.height;
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
centerX = rect.left + rect.width / 2;
|
|
60
|
+
centerY = rect.top + rect.height / 2;
|
|
61
|
+
// A transform-positioned host re-centers itself as it resizes (e.g.
|
|
62
|
+
// translate(-50%,-50%) centering), so resize SYMMETRICALLY from the center
|
|
63
|
+
// and the dragged edge/corner stays under the cursor. A static/anchored host
|
|
64
|
+
// instead grows from the opposite (fixed) edge.
|
|
65
|
+
symmetric = getComputedStyle(host).transform !== 'none';
|
|
53
66
|
|
|
54
67
|
handle.setPointerCapture(e.pointerId);
|
|
55
68
|
host.setAttribute('data-resizable-resizing', '');
|
|
56
|
-
host.setAttribute('data-resizable-edge',
|
|
69
|
+
host.setAttribute('data-resizable-edge', h.name);
|
|
57
70
|
});
|
|
58
71
|
|
|
59
72
|
handle.addEventListener('pointermove', (e) => {
|
|
60
|
-
if (!resizing ||
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
host.style.
|
|
66
|
-
} else
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
host.style.height = `${Math.max(0, startHeight
|
|
73
|
+
if (!resizing || active !== h.name) return;
|
|
74
|
+
if (symmetric) {
|
|
75
|
+
// Dragged edge/corner tracks the cursor; the host grows from its center
|
|
76
|
+
// (both sides) so the re-centering transform keeps it in place.
|
|
77
|
+
if (h.dw) host.style.width = `${Math.max(0, 2 * h.dw * (e.clientX - centerX))}px`;
|
|
78
|
+
if (h.dh) host.style.height = `${Math.max(0, 2 * h.dh * (e.clientY - centerY))}px`;
|
|
79
|
+
} else {
|
|
80
|
+
// Anchored: the opposite edge stays fixed; the dragged edge grows from it.
|
|
81
|
+
const dx = e.clientX - startX;
|
|
82
|
+
const dy = e.clientY - startY;
|
|
83
|
+
if (h.dw) host.style.width = `${Math.max(0, startWidth + h.dw * dx)}px`;
|
|
84
|
+
if (h.dh) host.style.height = `${Math.max(0, startHeight + h.dh * dy)}px`;
|
|
72
85
|
}
|
|
73
86
|
});
|
|
74
87
|
|
|
75
88
|
handle.addEventListener('pointerup', () => {
|
|
76
|
-
if (!resizing ||
|
|
89
|
+
if (!resizing || active !== h.name) return;
|
|
77
90
|
resizing = false;
|
|
78
|
-
|
|
91
|
+
active = null;
|
|
79
92
|
host.removeAttribute('data-resizable-resizing');
|
|
80
93
|
host.removeAttribute('data-resizable-edge');
|
|
81
94
|
|
|
@@ -17,4 +17,23 @@ describe('resizable', () => {
|
|
|
17
17
|
expect(host.hasAttribute('data-resizable-resizing')).toBe(false);
|
|
18
18
|
expect(host.hasAttribute('data-resizable-edge')).toBe(false);
|
|
19
19
|
});
|
|
20
|
+
|
|
21
|
+
it('creates 8 hit-zones — 4 edges + 4 corners (resize in x, y, and x/y)', () => {
|
|
22
|
+
const host = mountHost();
|
|
23
|
+
connectTrait(resizable, host);
|
|
24
|
+
const names = [...host.querySelectorAll('[data-resizable-handle]')]
|
|
25
|
+
.map((el) => el.dataset.resizableHandle);
|
|
26
|
+
expect(names).toHaveLength(8);
|
|
27
|
+
expect(names).toEqual(expect.arrayContaining([
|
|
28
|
+
'top', 'right', 'bottom', 'left',
|
|
29
|
+
'top-left', 'top-right', 'bottom-right', 'bottom-left',
|
|
30
|
+
]));
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('disconnect removes all hit-zones', () => {
|
|
34
|
+
const host = mountHost();
|
|
35
|
+
const inst = connectTrait(resizable, host);
|
|
36
|
+
inst.disconnect(host);
|
|
37
|
+
expect(host.querySelectorAll('[data-resizable-handle]')).toHaveLength(0);
|
|
38
|
+
});
|
|
20
39
|
});
|