@lotics/ui 45.10.0 → 45.10.1
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/AGENTS.md +70 -137
- package/docs/ai_patterns.md +88 -150
- package/docs/catalog.md +206 -284
- package/docs/composition.md +394 -518
- package/docs/data_entry.md +109 -155
- package/docs/reviewing.md +39 -55
- package/docs/templates.md +459 -423
- package/docs/testing.md +3 -7
- package/package.json +1 -1
- package/src/pressable_row.tsx +7 -5
- package/src/table.tsx +15 -14
package/docs/testing.md
CHANGED
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
Three kit anatomies where the accessibility tree says one thing and an automated
|
|
4
4
|
driver has to do another. Each is **by design** — the shape that makes the
|
|
5
5
|
component correct for a keyboard and a screen reader is the shape that defeats a
|
|
6
|
-
naive `click()` — so each will read as a bug the first time
|
|
7
|
-
reaction (`force: true`, or "the component is broken") costs a debugging session.
|
|
6
|
+
naive `click()` — so each will read as a bug the first time.
|
|
8
7
|
|
|
9
8
|
Everything here is true wherever the kit renders. The iframe that a Lotics app
|
|
10
9
|
runs inside adds one more rule on top — `lotics docs building_an_app` § 8.
|
|
@@ -25,9 +24,7 @@ So the a11y tree shows `button "Open ACME-1042"`, and clicking it fails:
|
|
|
25
24
|
subtree intercepts pointer events
|
|
26
25
|
```
|
|
27
26
|
|
|
28
|
-
That is the design working, not a defect
|
|
29
|
-
precisely so a pointer lands on the row rather than the door. Drive it the way a
|
|
30
|
-
mouse user does:
|
|
27
|
+
That is the design working, not a defect. Drive it the way a mouse user does:
|
|
31
28
|
|
|
32
29
|
- **click the row container** — the `generic [cursor=pointer]` wrapping the door;
|
|
33
30
|
the click bubbles to `PressableRow`
|
|
@@ -66,5 +63,4 @@ and the window are the right ones. From the dragged element,
|
|
|
66
63
|
|
|
67
64
|
Then check **both** halves: re-snapshot for the optimistic move, and re-read the
|
|
68
65
|
record to confirm the mutation actually persisted. An optimistic move that never
|
|
69
|
-
reached the server looks identical on screen
|
|
70
|
-
the second one.
|
|
66
|
+
reached the server looks identical on screen.
|
package/package.json
CHANGED
package/src/pressable_row.tsx
CHANGED
|
@@ -14,10 +14,11 @@ export interface PressableRowProps {
|
|
|
14
14
|
marked?: boolean;
|
|
15
15
|
/**
|
|
16
16
|
* - "register" (THE record-list default): a rounded row whose hover/open/`marked`
|
|
17
|
-
* wash spans the FULL row width (incl. nested controls);
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* wash spans the FULL row width (incl. nested controls); the wash BLEEDS outward
|
|
18
|
+
* and the content stays on the container's own edge, so a `Table` header and its
|
|
19
|
+
* cells still align. The `Table` draws NOTHING between rows — it spaces them by
|
|
20
|
+
* 4px and the wash is the only mark a row makes — every app inherits this
|
|
21
|
+
* register look.
|
|
21
22
|
* - "bleed" (legacy): px-20, square wash to the edges, `Divider`-separated.
|
|
22
23
|
* The pre-rounded register row — kept for an edge-to-edge data grid that
|
|
23
24
|
* genuinely wants hard rules, not the floating default.
|
|
@@ -143,7 +144,8 @@ const styles = StyleSheet.create({
|
|
|
143
144
|
paddingHorizontal: ROW_WASH_BLEED,
|
|
144
145
|
marginHorizontal: -ROW_WASH_BLEED,
|
|
145
146
|
},
|
|
146
|
-
// Square, full-bleed —
|
|
147
|
+
// Square, full-bleed — the pre-rounded register row, for a grid that draws its own
|
|
148
|
+
// rules between rows. The register variant draws none. Legacy.
|
|
147
149
|
bleed: {
|
|
148
150
|
paddingHorizontal: ROW_WASH_BLEED,
|
|
149
151
|
marginHorizontal: -ROW_WASH_BLEED,
|
package/src/table.tsx
CHANGED
|
@@ -181,9 +181,9 @@ export interface TableProps {
|
|
|
181
181
|
* THE columnar register — define `columns` once and the header band + every row's
|
|
182
182
|
* cell widths come from it, so they can't drift (no hand-rolled `W` map, no
|
|
183
183
|
* `<View style={{width}}>` per cell). Renders a full-bleed eyebrow header (a
|
|
184
|
-
* sortable column becomes a `SortHeader`) and its `TableRow` children,
|
|
185
|
-
*
|
|
186
|
-
* non-columnar list (entity piles, card stacks) use `PressableRow` directly.
|
|
184
|
+
* sortable column becomes a `SortHeader`) and its `TableRow` children, spaced by
|
|
185
|
+
* 4px with no rule between them. Compose `TableRow` / `TableCell` for the body.
|
|
186
|
+
* For a non-columnar list (entity piles, card stacks) use `PressableRow` directly.
|
|
187
187
|
*
|
|
188
188
|
* The register is container-responsive with no prop: when the measured width
|
|
189
189
|
* can't fit every column it drops droppable columns by `priority`, and below
|
|
@@ -312,10 +312,10 @@ export interface TableGroupProps {
|
|
|
312
312
|
* column: that is a sort, and it costs a band of chrome per value while telling
|
|
313
313
|
* them what the cell beside it says.
|
|
314
314
|
*
|
|
315
|
-
* The band separates itself with AIR rather than a rule, because
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
* beneath it, which would orphan the title from the rows it opens.
|
|
315
|
+
* The band separates itself with AIR rather than a rule, because the register
|
|
316
|
+
* already separates its own rows with air and keeps ONE line — the band capping
|
|
317
|
+
* the columns — so a second would compete with it. The heading takes no rule
|
|
318
|
+
* beneath it either, which would orphan the title from the rows it opens.
|
|
319
319
|
*
|
|
320
320
|
* A group's rows keep their own `ordinal` numbering if they carry one: restart
|
|
321
321
|
* inside each band, where the reader's question is "which of these" rather than
|
|
@@ -609,8 +609,8 @@ const styles = StyleSheet.create({
|
|
|
609
609
|
paddingTop: 16,
|
|
610
610
|
paddingBottom: 16,
|
|
611
611
|
},
|
|
612
|
-
// A hairline under the column header anchors the columns; the rows below it
|
|
613
|
-
//
|
|
612
|
+
// A hairline under the column header anchors the columns; the rows below it carry
|
|
613
|
+
// none — see the file header for why that boundary is the register's only rule.
|
|
614
614
|
headerBandFilled: {
|
|
615
615
|
// The literal neutral, not `accent_wash`: this band is a lid on the columns,
|
|
616
616
|
// never a "you are here", and reading it through the brand token made a
|
|
@@ -644,11 +644,12 @@ const styles = StyleSheet.create({
|
|
|
644
644
|
body: {
|
|
645
645
|
gap: 4,
|
|
646
646
|
},
|
|
647
|
-
// Air, not a rule. A band boundary is the LARGEST break inside a register and
|
|
648
|
-
//
|
|
649
|
-
//
|
|
650
|
-
//
|
|
651
|
-
//
|
|
647
|
+
// Air, not a rule. A band boundary is the LARGEST break inside a register, and the
|
|
648
|
+
// register does not rule the smallest one either — rows are spaced, not ruled — so
|
|
649
|
+
// a line here would be a second rule competing with the column band's, and the
|
|
650
|
+
// grouping stops reading. The first band's heading sits under the column band's own
|
|
651
|
+
// hairline, so it takes less top space than the ones that follow — handled by the
|
|
652
|
+
// heading's own padding rather than by the caller.
|
|
652
653
|
groupHeading: {
|
|
653
654
|
flexDirection: "row",
|
|
654
655
|
alignItems: "center",
|