@ankhorage/zora 25.5.0 → 25.6.2
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 +30 -0
- package/README.md +2 -1
- package/dist/capabilities/index.d.ts +2 -74
- package/dist/capabilities/index.d.ts.map +1 -1
- package/dist/capabilities/index.js +6158 -59
- package/dist/capabilities/index.js.map +118 -1
- package/dist/cli/index.d.ts +2 -74
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/features/grid-view/adapters/inbound/GridView.d.ts +2 -7
- package/dist/features/grid-view/adapters/inbound/GridView.d.ts.map +1 -1
- package/dist/features/grid-view/adapters/inbound/GridView.js +309 -51
- package/dist/features/grid-view/adapters/inbound/GridView.js.map +1 -1
- package/dist/features/grid-view/adapters/inbound/TileGrid.d.ts +1 -1
- package/dist/features/grid-view/adapters/inbound/TileGrid.d.ts.map +1 -1
- package/dist/features/grid-view/adapters/inbound/TileGrid.js +11 -4
- package/dist/features/grid-view/adapters/inbound/TileGrid.js.map +1 -1
- package/dist/features/matrix-grid/adapters/inbound/MatrixGrid.d.ts +5 -0
- package/dist/features/matrix-grid/adapters/inbound/MatrixGrid.d.ts.map +1 -0
- package/dist/features/matrix-grid/adapters/inbound/MatrixGrid.js +59 -0
- package/dist/features/matrix-grid/adapters/inbound/MatrixGrid.js.map +1 -0
- package/dist/features/matrix-grid/application/resolveMatrixGridContentSize.d.ts +7 -0
- package/dist/features/matrix-grid/application/resolveMatrixGridContentSize.d.ts.map +1 -0
- package/dist/features/matrix-grid/application/resolveMatrixGridContentSize.js +24 -0
- package/dist/features/matrix-grid/application/resolveMatrixGridContentSize.js.map +1 -0
- package/dist/features/matrix-grid/application/resolveMatrixGridSelection.d.ts +5 -0
- package/dist/features/matrix-grid/application/resolveMatrixGridSelection.d.ts.map +1 -0
- package/dist/features/matrix-grid/application/resolveMatrixGridSelection.js +8 -0
- package/dist/features/matrix-grid/application/resolveMatrixGridSelection.js.map +1 -0
- package/dist/features/matrix-grid/meta.d.ts +11 -0
- package/dist/features/matrix-grid/meta.d.ts.map +1 -0
- package/dist/features/matrix-grid/meta.js +11 -0
- package/dist/features/matrix-grid/meta.js.map +1 -0
- package/dist/features/matrix-grid/public.d.ts +4 -0
- package/dist/features/matrix-grid/public.d.ts.map +1 -0
- package/dist/features/matrix-grid/public.js +3 -0
- package/dist/features/matrix-grid/public.js.map +1 -0
- package/dist/features/registry/ZORA_COMPONENT_REGISTRY.d.ts.map +1 -1
- package/dist/features/registry/ZORA_COMPONENT_REGISTRY.js +2 -0
- package/dist/features/registry/ZORA_COMPONENT_REGISTRY.js.map +1 -1
- package/dist/features/registry/componentMeta.d.ts.map +1 -1
- package/dist/features/registry/componentMeta.js +2 -0
- package/dist/features/registry/componentMeta.js.map +1 -1
- package/dist/features/registry/createEventCapabilities.d.ts +4 -0
- package/dist/features/registry/createEventCapabilities.d.ts.map +1 -0
- package/dist/features/registry/createEventCapabilities.js +76 -0
- package/dist/features/registry/createEventCapabilities.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/types/grid-view.d.ts +18 -1
- package/dist/types/grid-view.d.ts.map +1 -1
- package/dist/types/grid-view.js.map +1 -1
- package/dist/types/matrix-grid.d.ts +23 -0
- package/dist/types/matrix-grid.d.ts.map +1 -0
- package/dist/types/matrix-grid.js +2 -0
- package/dist/types/matrix-grid.js.map +1 -0
- package/package.json +1822 -4
- package/src/capabilities/index.test.ts +87 -15
- package/src/capabilities/index.ts +5 -2
- package/src/cli/index.test.ts +5 -3
- package/src/cli/index.ts +5 -2
- package/src/features/grid-view/adapters/inbound/GridView.interaction.test.tsx +585 -0
- package/src/features/grid-view/adapters/inbound/GridView.test.tsx +74 -0
- package/src/features/grid-view/adapters/inbound/GridView.tsx +506 -77
- package/src/features/grid-view/adapters/inbound/TileGrid.tsx +26 -3
- package/src/features/matrix-grid/adapters/inbound/MatrixGrid.test.tsx +232 -0
- package/src/features/matrix-grid/adapters/inbound/MatrixGrid.tsx +142 -0
- package/src/features/matrix-grid/application/resolveMatrixGridContentSize.test.ts +32 -0
- package/src/features/matrix-grid/application/resolveMatrixGridContentSize.ts +28 -0
- package/src/features/matrix-grid/application/resolveMatrixGridSelection.test.ts +10 -0
- package/src/features/matrix-grid/application/resolveMatrixGridSelection.ts +15 -0
- package/src/features/matrix-grid/application/resolveMatrixGridVisibleCells.test.ts +35 -0
- package/src/features/matrix-grid/meta.ts +12 -0
- package/src/features/matrix-grid/public.ts +3 -0
- package/src/features/registry/ZORA_COMPONENT_REGISTRY.ts +2 -0
- package/src/features/registry/componentMeta.ts +2 -0
- package/src/features/registry/createEventCapabilities.ts +108 -0
- package/src/features/time-grid/adapters/inbound/TimeGrid.test.tsx +35 -8
- package/src/index.ts +2 -0
- package/src/structureOwnership.test.ts +5 -0
- package/src/types/grid-view.ts +27 -1
- package/src/types/matrix-grid.ts +29 -0
- package/web-dist/chunks/{Accordion-d6azgz09.js → Accordion-2r0gqk3x.js} +1 -1
- package/web-dist/chunks/Accordion-a6551mh4.js +515 -0
- package/web-dist/chunks/{Accordion-0my2z6qe.js → Accordion-bz04casa.js} +132 -3
- package/web-dist/chunks/{Accordion-7qfd4cb4.js → Accordion-jh72azm2.js} +1 -1
- package/web-dist/components/explorer/Explorer.js +2 -2
- package/web-dist/components/file-explorer/FileExplorer.js +2 -2
- package/web-dist/components/grid-line-overlay/GridLineOverlay.js +1 -1
- package/web-dist/components/grid-ruler/GridRuler.js +1 -1
- package/web-dist/components/grid-view/GridView.js +1 -1
- package/web-dist/components/matrix-grid/MatrixGrid.d.ts +3 -0
- package/web-dist/components/matrix-grid/MatrixGrid.js +153 -0
- package/web-dist/components/matrix-grid/index.d.ts +1 -0
- package/web-dist/components/matrix-grid/index.js +2 -0
- package/web-dist/components/media-explorer/MediaExplorer.js +2 -2
- package/web-dist/components/reader/Reader.js +1 -1
- package/web-dist/components/spatial-grid/SpatialGrid.js +1 -1
- package/web-dist/components/tile-grid/TileGrid.js +1 -1
- package/web-dist/components/time-grid/TimeGrid.js +2 -2
- package/web-dist/components/uploader/Uploader.js +2 -2
- package/web-dist/manifest.json +53 -24
- package/web-dist/chunks/Accordion-gxj5qbpr.js +0 -194
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { areCapabilitiesEqual, isCapabilityId } from '@ankhorage/capability';
|
|
2
|
+
import type { Capability } from '@ankhorage/contracts/capability';
|
|
3
|
+
import type { DataSchema } from '@ankhorage/contracts/data';
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
ZoraComponentEventMeta,
|
|
7
|
+
ZoraComponentEventPayloadFieldMeta,
|
|
8
|
+
} from '../../types/authoring';
|
|
9
|
+
import { ZORA_COMPONENT_META } from './componentMeta';
|
|
10
|
+
|
|
11
|
+
/*** Projects direct-manifest ZORA event metadata into unique portable event capabilities. */
|
|
12
|
+
export function createEventCapabilities(): readonly Capability[] {
|
|
13
|
+
const capabilitiesById = Object.values(ZORA_COMPONENT_META)
|
|
14
|
+
.filter((component) => component.directManifestNode)
|
|
15
|
+
.flatMap((component) => Object.values(component.events ?? {}))
|
|
16
|
+
.reduce<ReadonlyMap<Capability['id'], Capability>>(
|
|
17
|
+
(capabilities, event) => addEventCapability(capabilities, event),
|
|
18
|
+
new Map(),
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
return [...capabilitiesById.values()].sort((left, right) => left.id.localeCompare(right.id));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/*** Adds one namespaced metadata event while rejecting conflicting duplicate identities. */
|
|
25
|
+
function addEventCapability(
|
|
26
|
+
capabilities: ReadonlyMap<Capability['id'], Capability>,
|
|
27
|
+
event: ZoraComponentEventMeta,
|
|
28
|
+
): ReadonlyMap<Capability['id'], Capability> {
|
|
29
|
+
if (!isCapabilityId(event.eventType)) return capabilities;
|
|
30
|
+
|
|
31
|
+
const capability = createEventCapability(event);
|
|
32
|
+
const existing = capabilities.get(capability.id);
|
|
33
|
+
if (existing !== undefined && !areCapabilitiesEqual(existing, capability)) {
|
|
34
|
+
throw new Error(`ZORA event metadata defines conflicting capability "${capability.id}".`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return new Map([...capabilities, [capability.id, capability]]);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/*** Converts one emitted component event into its serializable canonical descriptor. */
|
|
41
|
+
function createEventCapability(event: ZoraComponentEventMeta): Capability {
|
|
42
|
+
if (!isCapabilityId(event.eventType)) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`ZORA event metadata must use a namespaced capability id: "${event.eventType}".`,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
id: event.eventType,
|
|
50
|
+
owner: '@ankhorage/zora',
|
|
51
|
+
access: ['emit'],
|
|
52
|
+
binding: { kind: 'event', bindableAs: ['source'] },
|
|
53
|
+
label: event.label,
|
|
54
|
+
...(event.description === undefined ? {} : { description: event.description }),
|
|
55
|
+
output: { schema: createEventPayloadSchema(event.payloadFields ?? []) },
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/*** Projects the documented event payload fields into an open object schema. */
|
|
60
|
+
function createEventPayloadSchema(
|
|
61
|
+
fields: readonly ZoraComponentEventPayloadFieldMeta[],
|
|
62
|
+
): DataSchema {
|
|
63
|
+
return {
|
|
64
|
+
type: 'object',
|
|
65
|
+
properties: fields.reduce<Readonly<Record<string, DataSchema>>>(addPayloadField, {}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/*** Adds one dotted metadata path to an immutable object-schema property map. */
|
|
70
|
+
function addPayloadField(
|
|
71
|
+
properties: Readonly<Record<string, DataSchema>>,
|
|
72
|
+
field: ZoraComponentEventPayloadFieldMeta,
|
|
73
|
+
): Readonly<Record<string, DataSchema>> {
|
|
74
|
+
return addPayloadFieldAtPath(properties, field.path.split('.'), createPayloadFieldSchema(field));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/*** Recursively embeds a leaf schema below its documented object-property path. */
|
|
78
|
+
function addPayloadFieldAtPath(
|
|
79
|
+
properties: Readonly<Record<string, DataSchema>>,
|
|
80
|
+
path: readonly string[],
|
|
81
|
+
schema: DataSchema,
|
|
82
|
+
): Readonly<Record<string, DataSchema>> {
|
|
83
|
+
const [key, ...remainingPath] = path;
|
|
84
|
+
if (key === undefined || key === '') return properties;
|
|
85
|
+
if (remainingPath.length === 0) return { ...properties, [key]: schema };
|
|
86
|
+
|
|
87
|
+
const current = Object.entries(properties).find(([propertyKey]) => propertyKey === key)?.[1];
|
|
88
|
+
const nestedProperties = addPayloadFieldAtPath(current?.properties ?? {}, remainingPath, schema);
|
|
89
|
+
return {
|
|
90
|
+
...properties,
|
|
91
|
+
[key]: { ...current, type: 'object', properties: nestedProperties },
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/*** Maps one authoring payload-field type and annotations to its portable data schema. */
|
|
96
|
+
function createPayloadFieldSchema(field: ZoraComponentEventPayloadFieldMeta): DataSchema {
|
|
97
|
+
return {
|
|
98
|
+
...(field.type === 'object'
|
|
99
|
+
? { type: 'object' as const }
|
|
100
|
+
: field.type === 'record'
|
|
101
|
+
? { type: 'object' as const, additionalProperties: true }
|
|
102
|
+
: field.type === 'unknown'
|
|
103
|
+
? {}
|
|
104
|
+
: { type: field.type }),
|
|
105
|
+
...(field.label === undefined ? {} : { title: field.label }),
|
|
106
|
+
...(field.description === undefined ? {} : { description: field.description }),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
@@ -105,22 +105,49 @@ test('keeps mounted interval and virtualized variable-height lane labels synchro
|
|
|
105
105
|
expect(arrowDown.defaultPrevented).toBe(true);
|
|
106
106
|
expect(focusedIds).toEqual(['strings']);
|
|
107
107
|
|
|
108
|
-
const verticalScroller =
|
|
109
|
-
|
|
110
|
-
element.getAttribute('style') === 'width: 200px; height: 30px;' &&
|
|
111
|
-
Array.from(element.querySelectorAll('div')).some(
|
|
112
|
-
(child) => child.getAttribute('style') === 'width: 200px; height: 180px;',
|
|
113
|
-
),
|
|
108
|
+
const verticalScroller = host.querySelector<HTMLElement>(
|
|
109
|
+
'[data-testid="time-grid-viewport-vertical-scroll"]',
|
|
114
110
|
);
|
|
115
111
|
if (!verticalScroller) throw new Error('Missing GridView vertical scroller');
|
|
116
|
-
|
|
112
|
+
verticalScroller.scrollTop = 60;
|
|
117
113
|
void act(() => verticalScroller.dispatchEvent(new browser.Event('scroll', { bubbles: true })));
|
|
118
114
|
|
|
119
|
-
expect(viewportOffsets).
|
|
115
|
+
expect(viewportOffsets).toEqual([30]);
|
|
120
116
|
expect(host.querySelector('[data-testid="time-grid-lane-label-drums"]')).toBeNull();
|
|
121
117
|
expect(
|
|
122
118
|
host.querySelector('[data-testid="time-grid-lane-label-bass"]')?.getAttribute('style'),
|
|
123
119
|
).toContain('top: -20px');
|
|
120
|
+
|
|
121
|
+
act(() => {
|
|
122
|
+
root.render(
|
|
123
|
+
<TimeGrid
|
|
124
|
+
contentWidth={100}
|
|
125
|
+
focusedIntervalId="strings"
|
|
126
|
+
height={30}
|
|
127
|
+
intervals={[
|
|
128
|
+
{ extent: 10, id: 'drums', laneId: 'drums', start: 0 },
|
|
129
|
+
{ extent: 10, id: 'strings', laneId: 'strings', start: 0 },
|
|
130
|
+
]}
|
|
131
|
+
lanes={[
|
|
132
|
+
{ height: 20, id: 'drums' },
|
|
133
|
+
{ height: 40, id: 'bass' },
|
|
134
|
+
{ height: 30, id: 'strings' },
|
|
135
|
+
]}
|
|
136
|
+
onFocusedIntervalIdChange={(id) => focusedIds.push(id)}
|
|
137
|
+
onViewportChange={(viewport) => viewportOffsets.push(viewport.offsetY)}
|
|
138
|
+
overscanPixels={0}
|
|
139
|
+
renderInterval={(interval, selected) => (
|
|
140
|
+
<span data-selected={selected}>{interval.id}</span>
|
|
141
|
+
)}
|
|
142
|
+
renderLaneLabel={(lane) => <span>{lane.id}</span>}
|
|
143
|
+
selectedIntervalIds={['strings']}
|
|
144
|
+
testID="time-grid"
|
|
145
|
+
width={100}
|
|
146
|
+
zoom={2}
|
|
147
|
+
/>,
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
expect(viewportOffsets).toEqual([30, 56]);
|
|
124
151
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
125
152
|
} finally {
|
|
126
153
|
act(() => root.unmount());
|
package/src/index.ts
CHANGED
|
@@ -314,6 +314,8 @@ export type {
|
|
|
314
314
|
} from './features/list/public';
|
|
315
315
|
export { FlatList, SectionList } from './features/list/public';
|
|
316
316
|
export { List, ListItem, ListSection } from './features/list/public';
|
|
317
|
+
export type { MatrixGridProps } from './features/matrix-grid/public';
|
|
318
|
+
export { MatrixGrid } from './features/matrix-grid/public';
|
|
317
319
|
export { MissingElement, type MissingElementProps } from './features/missing-element/public';
|
|
318
320
|
export { Pagination, type PaginationProps } from './features/pagination/public';
|
|
319
321
|
export type { PaletteItemProps } from './features/palette-item/public';
|
|
@@ -63,4 +63,9 @@ describe('src ownership', () => {
|
|
|
63
63
|
expect(existsSync(path), path).toBe(false);
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
|
+
|
|
67
|
+
test('keeps event capability projection with the registry metadata owner', () => {
|
|
68
|
+
expect(existsSync('src/features/registry/createEventCapabilities.ts')).toBe(true);
|
|
69
|
+
expect(existsSync('src/capabilities/createEventCapabilities.ts')).toBe(false);
|
|
70
|
+
});
|
|
66
71
|
});
|
package/src/types/grid-view.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
GridRectItem,
|
|
3
|
+
GridViewport,
|
|
4
|
+
GridViewportConstraints,
|
|
5
|
+
GridZoomLimits,
|
|
6
|
+
} from '@ankhorage/grid-view';
|
|
2
7
|
import type React from 'react';
|
|
3
8
|
|
|
4
9
|
import type { ZoraBaseProps } from './base';
|
|
@@ -10,6 +15,20 @@ export interface GridViewProps extends ZoraBaseProps {
|
|
|
10
15
|
contentHeight: number;
|
|
11
16
|
width: number;
|
|
12
17
|
height: number;
|
|
18
|
+
/**
|
|
19
|
+
* Canonical controlled world viewport. Supplying this value makes `onViewportChange`
|
|
20
|
+
* report interaction proposals without mutating renderer-owned state.
|
|
21
|
+
*/
|
|
22
|
+
viewport?: GridViewport;
|
|
23
|
+
/** Initial world position and independent axis scales for uncontrolled rendering. */
|
|
24
|
+
defaultViewport?: Partial<
|
|
25
|
+
Pick<GridViewport, 'offsetX' | 'offsetY' | 'pixelsPerUnitX' | 'pixelsPerUnitY'>
|
|
26
|
+
>;
|
|
27
|
+
/** Finite world bounds and optional overscroll for panning and focused-item reveal. */
|
|
28
|
+
viewportConstraints?: GridViewportConstraints;
|
|
29
|
+
/** Independent X/Y scale limits applied to focal-point zoom interactions. */
|
|
30
|
+
zoomLimits?: GridZoomLimits;
|
|
31
|
+
/** @deprecated Use `defaultViewport` for new code. */
|
|
13
32
|
zoom?: number;
|
|
14
33
|
overscanPixels?: number;
|
|
15
34
|
/** Stable item identity that must be scrolled into view without duplicating viewport geometry. */
|
|
@@ -34,11 +53,18 @@ export interface TileGridProps extends ZoraBaseProps {
|
|
|
34
53
|
tileSize?: number;
|
|
35
54
|
gap?: number;
|
|
36
55
|
zoom?: number;
|
|
56
|
+
viewport?: GridViewport;
|
|
57
|
+
defaultViewport?: Partial<
|
|
58
|
+
Pick<GridViewport, 'offsetX' | 'offsetY' | 'pixelsPerUnitX' | 'pixelsPerUnitY'>
|
|
59
|
+
>;
|
|
60
|
+
viewportConstraints?: GridViewportConstraints;
|
|
61
|
+
zoomLimits?: GridZoomLimits;
|
|
37
62
|
overscanPixels?: number;
|
|
38
63
|
focusedItemId?: string;
|
|
39
64
|
revealPaddingPixels?: number;
|
|
40
65
|
/** Reports the same measured column count used to position tiles. */
|
|
41
66
|
onColumnsChange?: (columns: number) => void;
|
|
67
|
+
onViewportChange?: (viewport: GridViewport) => void;
|
|
42
68
|
onVisibleItemIdsChange?: (ids: readonly string[]) => void;
|
|
43
69
|
renderItem: (item: TileGridItem) => React.ReactNode;
|
|
44
70
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
GridMatrixCell,
|
|
3
|
+
GridMatrixCellPlacement,
|
|
4
|
+
GridMatrixLayout,
|
|
5
|
+
GridViewport,
|
|
6
|
+
} from '@ankhorage/grid-view';
|
|
7
|
+
import type React from 'react';
|
|
8
|
+
|
|
9
|
+
import type { ZoraBaseProps } from './base';
|
|
10
|
+
import type { SelectionMode } from './selection';
|
|
11
|
+
|
|
12
|
+
/** Code-first virtualized sparse-matrix presentation over the published grid-view geometry API. */
|
|
13
|
+
export interface MatrixGridProps extends ZoraBaseProps {
|
|
14
|
+
readonly layout: GridMatrixLayout;
|
|
15
|
+
readonly cells: readonly GridMatrixCell[];
|
|
16
|
+
readonly width: number;
|
|
17
|
+
readonly height: number;
|
|
18
|
+
/** A supplied viewport is controlled by the caller, including independent axis zoom. */
|
|
19
|
+
readonly viewport?: GridViewport;
|
|
20
|
+
readonly zoomX?: number;
|
|
21
|
+
readonly zoomY?: number;
|
|
22
|
+
readonly overscanPixels?: number;
|
|
23
|
+
readonly selectedCellIds?: readonly string[];
|
|
24
|
+
readonly selectionMode?: SelectionMode;
|
|
25
|
+
readonly onSelectionChange?: (ids: readonly string[]) => void;
|
|
26
|
+
readonly onViewportChange?: (viewport: GridViewport) => void;
|
|
27
|
+
readonly renderCell: (cell: GridMatrixCellPlacement) => React.ReactNode;
|
|
28
|
+
readonly accessibilityLabel?: string;
|
|
29
|
+
}
|