@lotics/ui 38.1.0 → 39.0.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.
package/MIGRATION.md CHANGED
@@ -4,6 +4,31 @@ Breaking changes, newest first — normally per major, plus the rare minor that
4
4
  anyway (recorded under its exact version). The current contract lives in `AGENTS.md` + `docs/`;
5
5
  this file exists only to move an app from one release to the next.
6
6
 
7
+ ## 39.0.0 — `PageHeader.leading` is `trailing`, and it renders AFTER the title
8
+
9
+ 38.0.0 shipped `leading`, a slot before the title. It is now **`trailing`**, in the same
10
+ place in the props but rendered on the other side of the title text.
11
+
12
+ ```tsx
13
+ // 38.0.0
14
+ <PageHeader title="Members" leading={<IconButton …/>} actions={…} />
15
+ // 39.0.0
16
+ <PageHeader title="Members" trailing={<IconButton …/>} actions={…} />
17
+ ```
18
+
19
+ **Why the side changed.** The title is the page's first word. A control ahead of it makes
20
+ the eye parse chrome before it learns where it is, and on a page whose heading is the only
21
+ thing telling you which section you are in, that is the wrong order. After the title the
22
+ control still reads as part of the heading — which is the whole point of not putting it
23
+ with `actions` — without standing in front of it.
24
+
25
+ **Why a rename rather than a second slot.** A slot with no consumer is surface that has to
26
+ be understood by everyone who reads the component and used by no one; the kit's cull rule
27
+ says cut it. One slot for "a control belonging to the title" is the whole contract.
28
+
29
+ The layout law is unchanged and now covers both: the TITLE gives way and wraps, while
30
+ `trailing` and `actions` keep their width.
31
+
7
32
  ## 38.0.0 — the `lg` avatar is a control (40), not a size (48)
8
33
 
9
34
  `AVATAR_PX.lg` was 48 and `AVATAR_TEXT.lg` was `lg` type. They are now **40** and `md`
package/docs/catalog.md CHANGED
@@ -536,13 +536,15 @@ source (`src/<module>.tsx`/`.ts`) is the API reference.
536
536
  - **`container`** — `Container`: centers content at a max width (`ContainerSize` sm|md|lg,
537
537
  `CONTAINER_SIZES`).
538
538
  - **`page_header`** — `PageHeader`: the page's title band. `actions` puts page-level CTAs on
539
- the title row (right-aligned) and `leading` puts a control immediately BEFORE the title;
540
- `left`/`right` form a separate nav row above. Split `leading` from `actions` by what the
539
+ the title row (right-aligned) and `trailing` puts a control immediately AFTER the title;
540
+ `left`/`right` form a separate nav row above. Split `trailing` from `actions` by what the
541
541
  control acts on: `actions` do something to the page's CONTENT (create, sort, export),
542
- `leading` changes what is AROUND it (a side-panel toggle, a back arrow). A panel toggle
543
- filed under `actions` reads as a peer of "create one of these". Under a title too long
544
- for the row the TITLE gives way and wraps while `actions` keep their width — a wrapped
545
- title is merely taller, a CTA pushed off the row is unreachable.
542
+ `trailing` changes what is AROUND it (a side-panel toggle, a view switch). A panel toggle
543
+ filed under `actions` reads as a peer of "create one of these". It sits AFTER the title
544
+ because the title is the page's first word and nothing should come between the reader
545
+ and it. Under a title too long for the row the TITLE gives way and wraps while `trailing`
546
+ and `actions` keep their width — a wrapped title is merely taller, a control squeezed
547
+ below its own icon is broken.
546
548
  - **`page_content`** — `PageContent` + `PAGE_SIZES`: the page's padded, width-capped content
547
549
  region — a centred column with optional `title`/`titleRight`/`description`, `header`/`footer`
548
550
  slots and `fullscreen`. **Reach for it before hand-rolling a screen shell**: a scroller, a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/ui",
3
- "version": "38.1.0",
3
+ "version": "39.0.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./vite": {
@@ -10,32 +10,36 @@ interface PageHeaderProps {
10
10
  /** The nav row ABOVE the title, right-aligned. */
11
11
  right?: ReactNode;
12
12
  /**
13
- * A control that belongs to the TITLE, rendered immediately before it on the
14
- * title row — a panel toggle, a back arrow into the page you came from.
13
+ * A control that belongs to the TITLE, rendered immediately AFTER it on the
14
+ * title row — a panel toggle, a view switch, anything that reframes the page
15
+ * rather than acting on it.
15
16
  *
16
17
  * The distinction from `actions` is what the control acts ON, not where it
17
18
  * looks best. `actions` are things you do to the page's CONTENT (create, sort,
18
- * export) and collect at the right, where a scanning eye reaches them last;
19
- * `leading` changes what is AROUND the content, and belongs against the title
20
- * it frames. Putting a panel toggle in `actions` files it with the CTAs and
21
- * makes the reader parse "open a side panel" as a peer of "create one of
22
- * these".
19
+ * export) and collect at the far right, where a scanning eye reaches them
20
+ * last; `trailing` changes what is AROUND the content and stays with the title
21
+ * it qualifies, so it is read as part of the heading rather than as one more
22
+ * thing you can do to your list.
23
+ *
24
+ * It sits AFTER the title, not before, because the title is the page's first
25
+ * word and nothing should come between the reader and it — a control ahead of
26
+ * the heading makes the eye parse chrome before it learns where it is.
23
27
  */
24
- leading?: ReactNode;
28
+ trailing?: ReactNode;
25
29
  /** Page-level actions (CTAs), rendered on the title row, right-aligned —
26
30
  * distinct from `left`/`right`, which form a separate nav row above. */
27
31
  actions?: ReactNode;
28
32
  }
29
33
 
30
34
  export function PageHeader(props: PageHeaderProps) {
31
- const { title, description, left, right, leading, actions } = props;
35
+ const { title, description, left, right, trailing, actions } = props;
32
36
 
33
37
  const hasNav = !!left || !!right;
34
38
 
35
- // ONE shape, whichever slots are filled. Branching the row on `leading` gave
36
- // the title two different behaviours under a long string — shrinking when a
37
- // panel toggle happened to be present and overflowing when it was not — which
38
- // is a layout law decided by an unrelated prop.
39
+ // ONE shape, whichever slots are filled. Branching the row on the title's own
40
+ // slot gave the title two different behaviours under a long string — shrinking
41
+ // when a panel toggle happened to be present and overflowing when it was not —
42
+ // which is a layout law decided by an unrelated prop.
39
43
  //
40
44
  // The title is what gives way; `actions` keep their width, because a CTA
41
45
  // pushed off the row is unreachable while a wrapped title is merely taller.
@@ -62,10 +66,12 @@ export function PageHeader(props: PageHeaderProps) {
62
66
  minWidth: 0,
63
67
  }}
64
68
  >
65
- {leading}
66
69
  <Text size="xxl" weight="semibold" style={{ flexShrink: 1, minWidth: 0 }}>
67
70
  {title}
68
71
  </Text>
72
+ {/* Never shrinks: the title is what gives way, and a control squeezed
73
+ below its own icon is not a smaller control, it is a broken one. */}
74
+ {trailing !== undefined && <View style={{ flexShrink: 0 }}>{trailing}</View>}
69
75
  </View>
70
76
  {actions}
71
77
  </View>