machinalayout 0.1.0 → 0.2.0

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.
Files changed (45) hide show
  1. package/README.md +280 -49
  2. package/dist/chunk-BJOQRPPX.js +382 -0
  3. package/dist/chunk-HU6XYOH7.js +133 -0
  4. package/dist/chunk-KYWOCAHK.js +205 -0
  5. package/dist/chunk-RJYRJ3LD.js +0 -0
  6. package/dist/chunk-TR24ERZT.js +66 -0
  7. package/dist/dispatch/index.d.ts +49 -0
  8. package/dist/dispatch/index.js +217 -0
  9. package/dist/index.d.ts +15 -238
  10. package/dist/index.js +596 -591
  11. package/dist/react/index.d.ts +33 -0
  12. package/dist/react/index.js +7 -0
  13. package/dist/react-native/index.d.ts +30 -0
  14. package/dist/react-native/index.js +83 -0
  15. package/dist/text/index.d.ts +10 -0
  16. package/dist/text/index.js +9 -0
  17. package/dist/text/react/index.d.ts +14 -0
  18. package/dist/text/react/index.js +7 -0
  19. package/dist/text/react-native/index.d.ts +16 -0
  20. package/dist/text/react-native/index.js +155 -0
  21. package/dist/text/vue/index.d.ts +113 -0
  22. package/dist/text/vue/index.js +202 -0
  23. package/dist/types-BudfpzZX.d.ts +184 -0
  24. package/dist/types-C4poVJpR.d.ts +74 -0
  25. package/dist/vue/index.d.ts +173 -0
  26. package/dist/vue/index.js +111 -0
  27. package/docs/adapter-packaging-a0-plan.md +352 -0
  28. package/docs/adapters.md +19 -0
  29. package/docs/api-coherence-m8-audit.md +397 -0
  30. package/docs/error-codes.md +84 -0
  31. package/docs/grid-arrange-m5a-contract.md +480 -0
  32. package/docs/grid-arrange.md +51 -0
  33. package/docs/layout-interpolation.md +52 -0
  34. package/docs/machina-dispatch-d0-contract.md +496 -0
  35. package/docs/machina-dispatch.md +143 -0
  36. package/docs/named-layers.md +40 -0
  37. package/docs/react-adapter.md +51 -69
  38. package/docs/react-native-adapter.md +56 -0
  39. package/docs/react-native-text-renderer.md +50 -0
  40. package/docs/reference-alignment-m7a-contract.md +384 -0
  41. package/docs/reference-alignment.md +44 -0
  42. package/docs/responsive-variants.md +54 -0
  43. package/docs/vue-adapter.md +55 -0
  44. package/docs/vue-text-renderer.md +55 -0
  45. package/package.json +60 -5
@@ -0,0 +1,480 @@
1
+ # GridArrange design contract (M5a)
2
+
3
+ ## 1. Executive summary
4
+
5
+ This document defines the **design contract** for a future `GridArrange` runtime implementation in M5b.
6
+
7
+ > Status (May 11, 2026): M5b runtime implementation is now available in core.
8
+
9
+ `GridArrange` is introduced as an explicit, deterministic 2D arranger that fits the existing Machina model:
10
+
11
+ - rows are still authored as flat `LayoutRow[]`,
12
+ - parents own coordinate spaces,
13
+ - arrangers place direct children,
14
+ - resolved output remains rectangles,
15
+ - adapters (including React) continue to render resolved rectangles.
16
+
17
+ `GridArrange` is a narrow, explicit model for row/column placement and **is not** a CSS Grid clone.
18
+
19
+ ## 2. Goals
20
+
21
+ - Add a first-class 2D arranger as `ArrangeSpec`.
22
+ - Keep frame vs arrange responsibility intact:
23
+ - `frame` defines node rectangle,
24
+ - `arrange` defines how node places direct children.
25
+ - Require explicit child placement using a new `CellFrame` for direct children of grid parents.
26
+ - Keep resolution parent-rect driven and deterministic.
27
+ - Integrate with existing features: responsive variants, offset, z metadata, resolved tree, interpolation.
28
+ - Keep v1 scope narrow and implementation-ready for M5b.
29
+
30
+ ## 3. Non-goals
31
+
32
+ M5a and M5b v1 explicitly do **not** include:
33
+
34
+ - CSS Grid syntax or compatibility,
35
+ - auto-placement,
36
+ - implicit row/column creation,
37
+ - template areas,
38
+ - named lines,
39
+ - `minmax` or intrinsic track sizing,
40
+ - content measurement / DOM measurement,
41
+ - subgrid,
42
+ - masonry,
43
+ - per-cell margins,
44
+ - percentage string units,
45
+ - `UiLength` tracks,
46
+ - grid-level align/justify negotiation,
47
+ - graph mutation (add/remove nodes via variants).
48
+
49
+ ## 4. Type proposal
50
+
51
+ ### 4.1 `ArrangeSpec`
52
+
53
+ `GridArrange` is added as an arrange type.
54
+
55
+ ```ts
56
+ export type ArrangeSpec =
57
+ | StackArrange
58
+ | GridArrange;
59
+ ```
60
+
61
+ ### 4.2 `CellFrame`
62
+
63
+ Direct children of grid parents use a new `CellFrame`.
64
+
65
+ ```ts
66
+ export type CellFrame = {
67
+ kind: "cell";
68
+ col: number;
69
+ row: number;
70
+ colSpan?: number;
71
+ rowSpan?: number;
72
+ };
73
+ ```
74
+
75
+ `FrameSpec` proposal:
76
+
77
+ ```ts
78
+ export type FrameSpec =
79
+ | RootFrame
80
+ | AbsoluteFrame
81
+ | AnchorFrame
82
+ | FixedFrame
83
+ | FillFrame
84
+ | CellFrame;
85
+ ```
86
+
87
+ ### 4.3 `GridTrack`
88
+
89
+ Grid tracks are explicit records (not `number | "fill"`).
90
+
91
+ ```ts
92
+ export type GridTrack =
93
+ | { kind: "fixed"; size: number }
94
+ | { kind: "fill"; weight?: number };
95
+ ```
96
+
97
+ ### 4.4 `GridArrange`
98
+
99
+ ```ts
100
+ export type GridArrange = {
101
+ kind: "grid";
102
+ columns: GridTrack[];
103
+ rows: GridTrack[];
104
+ columnGap?: number;
105
+ rowGap?: number;
106
+ padding?: number | EdgeInsets;
107
+ };
108
+ ```
109
+
110
+ Defaults:
111
+
112
+ - `columnGap = 0`
113
+ - `rowGap = 0`
114
+ - `padding = 0`
115
+
116
+ ## 5. Semantics
117
+
118
+ ### 5.1 Placement model
119
+
120
+ - `GridArrange` only affects placement of **direct children**.
121
+ - If a parent has `arrange.kind === "grid"`, every direct child frame must be `CellFrame`.
122
+ - Children of those child nodes resolve using normal existing rules (their own frame + optional arrange).
123
+
124
+ ### 5.2 Indexing and spans
125
+
126
+ - `row` and `col` are **zero-based** indexes.
127
+ - `colSpan` defaults to `1`.
128
+ - `rowSpan` defaults to `1`.
129
+ - Spans must be positive integers.
130
+ - No implicit placement, no next-cell flow.
131
+
132
+ ### 5.3 Track semantics
133
+
134
+ - `fixed`: explicit px size, finite and `>= 0`.
135
+ - `fill`: proportional share of remaining space by weight.
136
+ - `fill.weight` default is `1`, must be finite and `> 0`.
137
+ - Fractional resolved sizes are allowed.
138
+ - No rounding step.
139
+ - No `UiLength` tracks in v1.
140
+
141
+ ### 5.4 Content rect semantics
142
+
143
+ Given parent rect `R` and normalized padding `P`:
144
+
145
+ - `content.x = R.x + P.left`
146
+ - `content.y = R.y + P.top`
147
+ - `content.width = R.width - P.left - P.right`
148
+ - `content.height = R.height - P.top - P.bottom`
149
+
150
+ If `content.width < 0` or `content.height < 0`, resolution fails with `GridContentNegative`.
151
+
152
+ ## 6. Validation and error codes
153
+
154
+ New grid-specific error codes:
155
+
156
+ ```ts
157
+ | "CellFrameWithoutGrid"
158
+ | "GridChildMustBeCell"
159
+ | "InvalidGridTrack"
160
+ | "InvalidGridCell"
161
+ | "GridContentNegative"
162
+ | "GridOverflow"
163
+ ```
164
+
165
+ ### 6.1 `InvalidGridTrack`
166
+
167
+ Used for invalid grid arrange/track config, including:
168
+
169
+ - `columns.length === 0`,
170
+ - `rows.length === 0`,
171
+ - fixed size non-finite or `< 0`,
172
+ - fill weight non-finite or `<= 0`,
173
+ - `columnGap`/`rowGap` non-finite or `< 0`.
174
+
175
+ ### 6.2 `InvalidGridCell`
176
+
177
+ Used for invalid cell coordinate/span config, including:
178
+
179
+ - `row`/`col` non-integer,
180
+ - `row`/`col < 0`,
181
+ - span non-integer,
182
+ - span `<= 0`,
183
+ - out-of-range span (`row + rowSpan > rows.length`, `col + colSpan > columns.length`).
184
+
185
+ ### 6.3 `GridChildMustBeCell`
186
+
187
+ Used when a node under a `grid` parent has any non-`cell` frame kind.
188
+
189
+ ### 6.4 `CellFrameWithoutGrid`
190
+
191
+ Used when:
192
+
193
+ - `resolveFrame` is called directly with `CellFrame`,
194
+ - or a child uses `CellFrame` under a non-grid parent.
195
+
196
+ ### 6.5 `GridContentNegative`
197
+
198
+ Used when normalized padding yields negative content width or height.
199
+
200
+ ### 6.6 `GridOverflow`
201
+
202
+ Used when, for an axis:
203
+
204
+ `contentAxisSize - fixedTotal - gapTotal < 0`.
205
+
206
+ ## 7. Resolution algorithm
207
+
208
+ ### 7.1 Axis track resolution (columns or rows)
209
+
210
+ Inputs:
211
+
212
+ - `contentAxisSize`,
213
+ - `tracks`,
214
+ - `gap`,
215
+ - axis label for diagnostics.
216
+
217
+ Compute:
218
+
219
+ 1. `fixedTotal = sum(fixed.size)`
220
+ 2. `gapTotal = gap * max(0, tracks.length - 1)`
221
+ 3. `remaining = contentAxisSize - fixedTotal - gapTotal`
222
+
223
+ Rules:
224
+
225
+ - If `remaining < 0` -> `GridOverflow`.
226
+ - If fill tracks exist:
227
+ - `totalWeight = sum(fill.weight ?? 1)`
228
+ - each fill size = `remaining * weight / totalWeight`
229
+ - If no fill tracks exist:
230
+ - leave trailing `remaining` unused at axis end.
231
+ - No track justification in v1.
232
+ - No auto gap expansion.
233
+
234
+ Output per track:
235
+
236
+ - resolved `size`,
237
+ - `start` offset from content-axis origin.
238
+
239
+ ### 7.2 Child cell rectangle resolution
240
+
241
+ For child `CellFrame` with defaults applied (`rowSpan = 1`, `colSpan = 1`):
242
+
243
+ 1. Validate cell coordinates/spans.
244
+ 2. Resolve position:
245
+ - `x = content.x + columnStarts[col]`
246
+ - `y = content.y + rowStarts[row]`
247
+ 3. Resolve span size:
248
+ - `width = sum(columnSizes[col..col+colSpan-1]) + columnGap * (colSpan - 1)`
249
+ - `height = sum(rowSizes[row..row+rowSpan-1]) + rowGap * (rowSpan - 1)`
250
+ 4. Apply node `offset` post-placement using existing semantics:
251
+ - x offset resolves against **parent rect width**,
252
+ - y offset resolves against **parent rect height**,
253
+ - offset does not affect sibling placement or track resolution.
254
+
255
+ ## 8. Interaction with existing features
256
+
257
+ ### 8.1 StackArrange
258
+
259
+ - Stack remains the ordered 1D arranger.
260
+ - Grid is an additional arranger type, not a stack replacement.
261
+ - No behavior change to existing stack resolution.
262
+
263
+ ### 8.2 Responsive variants
264
+
265
+ - `variants` may override `arrange` to `GridArrange`.
266
+ - `variants` may override child `frame` to `CellFrame`.
267
+ - No special-case variant resolver logic is required.
268
+ - Existing constraint remains: variants cannot add/remove rows.
269
+
270
+ ### 8.3 Offset
271
+
272
+ - Offset stays node-local post-placement.
273
+ - Grid placement determines base rect, then existing offset machinery is applied.
274
+
275
+ ### 8.4 z
276
+
277
+ - Existing sibling-local bounded `z` behavior is unchanged.
278
+ - Grid impacts geometry only.
279
+
280
+ ### 8.5 Resolved tree
281
+
282
+ - `ResolvedLayoutDocument` preserves selected `arrange`/`frame` metadata, including `grid` and `cell`.
283
+ - `toResolvedTree` and flattening require no grid-specific branching beyond type acceptance.
284
+
285
+ ### 8.6 lerp
286
+
287
+ - `lerpResolvedLayouts` already interpolates resolved rectangles.
288
+ - No special interpolation path required for grid metadata.
289
+
290
+ ### 8.7 React adapter
291
+
292
+ - No adapter changes are required.
293
+ - Adapter consumes resolved rectangles; grid is core resolver-only behavior.
294
+
295
+ ## 9. Examples
296
+
297
+ ### 9.1 Simple 2x2 grid
298
+
299
+ ```ts
300
+ {
301
+ id: "grid",
302
+ parent: "root",
303
+ frame: { kind: "anchor", left: 0, right: 0, top: 0, bottom: 0 },
304
+ arrange: {
305
+ kind: "grid",
306
+ columns: [{ kind: "fill" }, { kind: "fill" }],
307
+ rows: [{ kind: "fixed", size: 100 }, { kind: "fill" }],
308
+ columnGap: 8,
309
+ rowGap: 8,
310
+ padding: 16,
311
+ },
312
+ }
313
+
314
+ {
315
+ id: "a",
316
+ parent: "grid",
317
+ frame: { kind: "cell", row: 0, col: 0 },
318
+ view: "Card",
319
+ }
320
+ ```
321
+
322
+ ### 9.2 Dashboard cards with fill columns
323
+
324
+ ```ts
325
+ {
326
+ id: "dashboard",
327
+ parent: "root",
328
+ frame: { kind: "anchor", left: 0, right: 0, top: 0, bottom: 0 },
329
+ arrange: {
330
+ kind: "grid",
331
+ columns: [
332
+ { kind: "fill", weight: 2 },
333
+ { kind: "fill", weight: 1 },
334
+ { kind: "fill", weight: 1 },
335
+ ],
336
+ rows: [{ kind: "fixed", size: 160 }, { kind: "fixed", size: 220 }],
337
+ columnGap: 12,
338
+ rowGap: 12,
339
+ padding: { top: 16, right: 16, bottom: 16, left: 16 },
340
+ },
341
+ }
342
+ ```
343
+
344
+ ### 9.3 Spanning child
345
+
346
+ ```ts
347
+ {
348
+ id: "chart",
349
+ parent: "grid",
350
+ frame: { kind: "cell", row: 1, col: 0, colSpan: 2 },
351
+ view: "Chart",
352
+ }
353
+ ```
354
+
355
+ ### 9.4 Responsive variant example
356
+
357
+ Base:
358
+
359
+ - parent uses a 3-column grid,
360
+ - cards A/B/C have explicit `CellFrame` positions.
361
+
362
+ Narrow variant:
363
+
364
+ - parent switches to one column,
365
+ - A/B/C each override `frame` to new `row`/`col` values.
366
+
367
+ ```ts
368
+ {
369
+ id: "grid",
370
+ parent: "root",
371
+ frame: { kind: "anchor", left: 0, right: 0, top: 0, bottom: 0 },
372
+ arrange: {
373
+ kind: "grid",
374
+ columns: [{ kind: "fill" }, { kind: "fill" }, { kind: "fill" }],
375
+ rows: [{ kind: "fixed", size: 120 }, { kind: "fixed", size: 120 }],
376
+ columnGap: 8,
377
+ rowGap: 8,
378
+ },
379
+ variants: [
380
+ {
381
+ when: { maxWidth: 700 },
382
+ arrange: {
383
+ kind: "grid",
384
+ columns: [{ kind: "fill" }],
385
+ rows: [
386
+ { kind: "fixed", size: 120 },
387
+ { kind: "fixed", size: 120 },
388
+ { kind: "fixed", size: 120 },
389
+ ],
390
+ rowGap: 8,
391
+ },
392
+ },
393
+ ],
394
+ }
395
+
396
+ {
397
+ id: "cardA",
398
+ parent: "grid",
399
+ frame: { kind: "cell", row: 0, col: 0 },
400
+ variants: [{ when: { maxWidth: 700 }, frame: { kind: "cell", row: 0, col: 0 } }],
401
+ }
402
+
403
+ {
404
+ id: "cardB",
405
+ parent: "grid",
406
+ frame: { kind: "cell", row: 0, col: 1 },
407
+ variants: [{ when: { maxWidth: 700 }, frame: { kind: "cell", row: 1, col: 0 } }],
408
+ }
409
+ ```
410
+
411
+ ## 10. Implementation plan for M5b
412
+
413
+ 1. Add `GridTrack`, `GridArrange`, `CellFrame` types and new error codes.
414
+ 2. Update `resolveFrame` to reject `CellFrame` outside grid path (`CellFrameWithoutGrid`).
415
+ 3. Add an internal grid axis track resolution helper.
416
+ 4. Add an internal grid child-cell rectangle helper.
417
+ 5. Extend `resolveLayoutDocument` parent-arranger branch for `arrange.kind === "grid"`.
418
+ 6. Preserve metadata through existing resolved document/tree/flatten/lerp paths.
419
+ 7. Add resolver and integration tests.
420
+ 8. Update docs/README references for new runtime support once landed.
421
+
422
+ ## 11. Test plan for M5b
423
+
424
+ ### 11.1 Types/API
425
+
426
+ - `GridTrack`, `GridArrange`, `CellFrame` importability/public typing coverage.
427
+
428
+ ### 11.2 Track resolution
429
+
430
+ - fixed tracks,
431
+ - fill tracks,
432
+ - weighted fill,
433
+ - mixed fixed + fill,
434
+ - gap handling,
435
+ - padding handling,
436
+ - overflow -> `GridOverflow`.
437
+
438
+ ### 11.3 Cell placement
439
+
440
+ - basic cell placement,
441
+ - row/column starts,
442
+ - `colSpan`,
443
+ - `rowSpan`,
444
+ - gaps included across spans,
445
+ - fractional fill size propagation.
446
+
447
+ ### 11.4 Validation
448
+
449
+ - empty rows/columns,
450
+ - invalid fixed size,
451
+ - invalid fill weight,
452
+ - negative or non-finite gaps,
453
+ - padding causing negative content,
454
+ - invalid row/col values,
455
+ - invalid spans,
456
+ - out-of-range cell spans,
457
+ - non-cell direct child under grid,
458
+ - cell child under non-grid.
459
+
460
+ ### 11.5 Integration
461
+
462
+ - nested grids,
463
+ - grid child with its own `StackArrange`,
464
+ - grid + offsets,
465
+ - grid + sibling-local `z`,
466
+ - responsive variant selecting grid arrange and cell frames,
467
+ - `lerpResolvedLayouts` between grid-resolved documents.
468
+
469
+ ## 12. Risks and mitigations
470
+
471
+ - **Risk: scope drift toward CSS Grid.**
472
+ **Mitigation:** keep explicit forbidden list and grid-specific validation/errors.
473
+ - **Risk: ambiguity around child frame legality.**
474
+ **Mitigation:** enforce strict direct-child `CellFrame` rule with dedicated errors.
475
+ - **Risk: hidden behavior via auto-placement pressure.**
476
+ **Mitigation:** explicit row/col required in all cases.
477
+ - **Risk: incompatibility concerns with existing adapters.**
478
+ **Mitigation:** preserve resolved-rectangle boundary; no adapter coupling.
479
+ - **Risk: future extension pressure (`UiLength` tracks, alignment modes).**
480
+ **Mitigation:** document as deferred v2 topics and keep M5b implementation narrow.
@@ -0,0 +1,51 @@
1
+ # GridArrange runtime (M5b)
2
+
3
+ `GridArrange` adds explicit deterministic 2D placement to MachinaLayout. It places direct children into declared rows/columns and resolves normal rectangles for downstream renderers.
4
+
5
+ ## Types
6
+
7
+ - `GridTrack`: `{ kind: "fixed", size }` or `{ kind: "fill", weight? }`
8
+ - `GridArrange`: `{ kind: "grid", columns, rows, columnGap?, rowGap?, padding? }`
9
+ - `CellFrame`: `{ kind: "cell", row, col, rowSpan?, colSpan? }`
10
+
11
+ ## Behavior
12
+
13
+ - Only direct children of a grid parent may use `CellFrame`.
14
+ - Grid computes a content rect from parent rect minus padding.
15
+ - Fixed tracks consume fixed space; fill tracks split remaining space by weight.
16
+ - Gaps are explicit; no justify, no auto-gap expansion.
17
+ - Cell spans include internal gaps.
18
+ - Offset is applied after cell placement using existing `applyOffset` semantics.
19
+
20
+ ## Validation / error codes
21
+
22
+ - `InvalidGridTrack`: invalid columns/rows/track values/gaps.
23
+ - `InvalidGridCell`: invalid row/col/spans or out-of-range.
24
+ - `GridChildMustBeCell`: grid parent has non-cell direct child.
25
+ - `CellFrameWithoutGrid`: cell resolved outside grid arranger path.
26
+ - `GridContentNegative`: padding makes content width/height negative.
27
+ - `GridOverflow`: fixed tracks + gaps exceed content size.
28
+
29
+ ## Example
30
+
31
+ ```ts
32
+ {
33
+ id: "root",
34
+ frame: { kind: "root" },
35
+ arrange: {
36
+ kind: "grid",
37
+ columns: [{ kind: "fixed", size: 100 }, { kind: "fill" }],
38
+ rows: [{ kind: "fixed", size: 40 }, { kind: "fill" }],
39
+ columnGap: 8,
40
+ rowGap: 8,
41
+ padding: 8,
42
+ },
43
+ }
44
+ ```
45
+
46
+ ## Limitations
47
+
48
+ - Not CSS Grid compatible.
49
+ - No auto-placement.
50
+ - No implicit tracks.
51
+ - No template areas/named lines/minmax/subgrid.
@@ -0,0 +1,52 @@
1
+ # Layout interpolation (M4a)
2
+
3
+ MachinaLayout includes pure helpers for interpolating **already resolved** layout documents:
4
+
5
+ - `lerpNumber(a, b, t)`
6
+ - `lerpRect(a, b, t)`
7
+ - `lerpResolvedLayouts(a, b, t)`
8
+
9
+ ## Boundary
10
+
11
+ Interpolation happens after layout resolution. MachinaLayout remains geometry authority, but it does **not** own animation timing.
12
+
13
+ Typical flow:
14
+
15
+ 1. Author collapsed rows and resolve.
16
+ 2. Author expanded rows and resolve.
17
+ 3. Drive `t` from your own animation source (spring/RAF/timeline).
18
+ 4. Call `lerpResolvedLayouts(collapsed, expanded, t)`.
19
+ 5. Render the result via `MachinaReactView`.
20
+
21
+ ## Compatibility requirement
22
+
23
+ `lerpResolvedLayouts` only supports compatible resolved documents:
24
+
25
+ - same `rootId`
26
+ - same node id set
27
+ - same parent/children structure
28
+ - same child ordering for every parent
29
+ - root id exists in both node maps
30
+
31
+ If compatibility fails, it throws `MachinaLayoutError` with code `"IncompatibleLayouts"`.
32
+
33
+ ## Numeric behavior
34
+
35
+ - linear interpolation only: `a + (b - a) * t`
36
+ - no clamping and no rounding
37
+ - `t < 0` and `t > 1` are allowed (overshoot supported)
38
+ - non-finite numbers throw `"NonFiniteNumber"`
39
+
40
+ ## Metadata behavior
41
+
42
+ `lerpResolvedLayouts` interpolates only `rect` fields. Other node metadata is preserved from the **end** layout `b` so `t=1` matches `b` structurally and semantically.
43
+
44
+ ## Current limitations
45
+
46
+ M4a does not support:
47
+
48
+ - graph morphing (enter/exit nodes)
49
+ - reordering children during interpolation
50
+ - metadata interpolation (`z`, `view`, `frame`, etc.)
51
+ - text/style/color interpolation
52
+ - animation loops, timers, or spring ownership