1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
//! The renderer-agnostic half of the make-family design system.
//!
//! <!-- wiki: makeover-layout -->
//!
//! `makeover` answers *what colour*, and varies by theme. `makeover-geometry`
//! answers *how much space*, and varies by density and surface. This crate
//! answers *what the thing is*, and varies by nothing.
//!
//! # The deferral rule
//!
//! A description names intents and relationships, never values. Say
//! [`Fill::Raised`], never `#D9DDF4`. Say `Gap::Peer`, never `6px`. What is
//! left once colour and spacing are deferred is **composition**: which edges
//! are lit, what inverts on press, what nests in what.
//!
//! The constraint that shapes all of it: a renderer that can only paint
//! rectangles has to be able to express the result. egui has no
//! `box-shadow: inset` and one stroke per widget with no per-side control; a
//! terminal has box-drawing characters and one cell of resolution, and cannot
//! draw a two-tone lit edge at all. A description that assumes per-side edges
//! is a CSS description wearing a neutral name. So this crate names the
//! *intent* — this region is a well — and each renderer chooses an expression
//! it can actually produce, including dropping half of one.
//!
//! # Scope
//!
//! - **Depth.** [`Bevel`], [`Edge`], [`Fill`], [`Depth`]: the bevel and the
//! surfaces it shapes. Fill and bevel are named together, so a raised bevel
//! over a recessed fill is unrepresentable.
//! - **Components.** [`Token`] (badge against chip), [`Notice`] (toast against
//! banner), [`RowPart`], [`CellPart`], [`Heading`], [`Selector`],
//! [`Readiness`], [`Awaiting`], [`Meter`], [`Figure`], [`Track`],
//! and [`Tone`], the one intent family they share.
//! - **Schemas.** [`Field`] for forms, [`Column`] for lists and tables,
//! [`Facet`] for the dimensions a set is narrowed by.
//! - **Structure.** [`Region`] for the parts of a screen, [`Arrangement`] for
//! how a screen is put together, [`Showing`] for how many of a region's
//! children are visible at once.
//!
//! # What a member is admitted on
//!
//! A member is added when an app needs a fact the vocabulary cannot state, and
//! refused when what it wants is presentation it should be asking a renderer
//! for. Three tests, all of which have to pass:
//!
//! - **Generic against bespoke.** Is this furniture any app would have, or is
//! it this app's own? A rule that withholds a word until a second app has
//! duplicated the code guarantees the duplication. What the app owns
//! keeps [`Region::Handover`] and [`Region::Ceded`].
//! - **Every host has an honest answer.** A member no renderer can express
//! without borrowing one host's idiom is not a description.
//! - **It can be laid out before it is filled.** See *First paint is final
//! paint* below.
//!
//! Count the members a thing needs before refusing it. A refusal is only worth
//! as much as the measurement under it.
//!
//! # What this crate cannot say
//!
//! - **An address.** What a control calls, and where a button goes. [`Act`]
//! names the act and holds no destination.
//! - **A current value.** A webview reads it out of the DOM and an
//! immediate-mode renderer holds a `&mut` to the app's own field. A
//! description carrying it would be a form model.
//! - **What has focus.** See below.
//! - **A duration or a clock.** No estimate of time remaining, no autosave
//! interval, no animation length.
//! - **A colour, a size or a position.** The deferral rule.
//!
//! # Reach, focus and the focus ring
//!
//! Three terms, and no others, for what sits outside the description.
//! **Reach** is which things can take focus and in what order; a browser reads
//! it off the document, a TUI derives it from draw order, egui from its own id
//! stack. **Focus** is which reached thing has the keyboard right now: the
//! renderer's, live, never described and never round-tripped through a
//! description. The **focus ring** is the visible cue; the token (`focus-ring`,
//! derived by `makeover` from the action colour) is the one shared artifact and
//! the drawing is the renderer's. Retired as names for any of this: "focus
//! stroke", "focus cue", "wants focus". "Caret" is a different thing — the text
//! cursor inside a field — and keeps its name.
//!
//! # The three tones, and what a colour claims
//!
//! One rule for how colour says whether a thing can be
//! used. Every renderer answers to it, and it is stated here because the
//! description is what names the intents.
//!
//! | the thing | intent |
//! |-----------|--------|
//! | active, emphasised, the thing itself | `content` |
//! | inactive but usable: it still answers a press | `content-secondary` |
//! | inert: disabled, or not a control at all | `content-muted` |
//!
//! `content-muted` is the one with a claim in it. [`State::Disabled`] resolves
//! to it, so a live control wearing it is telling the user it will not answer,
//! and being wrong about that is worse than being quiet, because the user's
//! response is to stop trying. A sortable column heading that was never sorted,
//! and every unchosen option in a radio group, read as dead lists if they wear
//! it. What is legitimately muted is a caption, a hint, a placeholder, a meter's reading, an axis label: text that
//! was never going to answer anything.
//!
//! The three are one ramp and not three colours. `makeover`'s `Emphasis` derives
//! the quieter two from the ink, so "one step back" means the same distance in
//! every theme and a renderer cannot land between them by picking its own.
//!
//! # First paint is final paint
//!
//! Nothing may change size or position after it is
//! first drawn, and nothing may stand in for content that has not arrived yet.
//! Both halves are absolute.
//!
//! It is stated here, rather than left to each renderer, because a renderer can
//! only reserve space the description gave it enough to size. A member whose
//! size depends on its content therefore owes whatever makes it sizeable while
//! the content is still absent, and that is the second admission test for a new
//! member: not only does it compose something this crate already names, it can
//! be laid out before it is filled.
//!
//! The mechanism is a reservation, and [`Sort`]'s caret is the worked example.
//! The caret is drawn into a box its own width whether or not the column is
//! sorted, so pressing a heading cannot reflow the row it sits in. The box names
//! no magnitude, which is what keeps it out of `makeover-geometry`'s territory.
//! Reserve from what is known; never discover geometry from what has not
//! arrived.
//!
//! The trap is an `Option` that means "not yet". [`Readiness::Pending`] is the
//! honest way to say a region is still waiting. An optional *measurement* is
//! not: a count that shows up later widens the text that prints it and moves
//! everything beside it, which is the reflow this rule exists to forbid. So an
//! `Option` on a measurement means the host will never know it — a property of
//! the query, fixed for the life of the screen — and a renderer sizes for the
//! answer it was handed rather than for the one it hopes is coming.
//!
//! # Any width, one answer
//!
//! The sibling of the rule above. That one is
//! independence from *when*; this one is independence from *how you got here*.
//!
//! A rendering is a pure function of the description and the viewport. The same
//! description at the same width is the same output, whatever widths came
//! before it. No renderer may carry geometry across frames, and none may narrow
//! by counting.
//!
//! The failure this forbids is ordinary enough to be the default everywhere
//! else: a page that hides its sidebar below some width, remembers that it hid
//! it, and does not bring it back the same way. Layout there is a function of
//! `(width, history)`, so dragging a window to 900 wide is a different screen
//! depending on whether you came from 1400 or from 600. Nobody chose that; it
//! is what measuring and remembering produce.
//!
//! The mechanism is [`Width`] for what grows and [`Priority`] for what drops.
//! Both are declared, both are read off the description, and neither needs a
//! measurement. A renderer narrows by raising a cutoff over a total order,
//! never by counting what fits and stopping — `makeover-tui`'s table states
//! that as its own rule and tests it, and `makeover-webview` reaches the same
//! place with `@media` and `display: none`, which is path-independent by
//! construction because CSS has nowhere to keep the previous width.
//!
//! Two things follow for anything new. A member that would need last frame's
//! size to lay out this frame is refused, the same way a member that cannot be
//! sized before it is filled is refused. And a fact about what disappears
//! belongs in the description, because a host that has to infer it can only
//! infer it from a measurement.
//!
//! # Where the description stops
//!
//! A member is added when an app needs a fact the vocabulary cannot state, and
//! refused when what it wants is presentation it should be asking a renderer
//! for. It is not a quota, and the goal is every screen described.
//!
//! A timeline is describable. What it needs and could not previously get is two
//! integers, where a thing starts and how long it lasts, which is [`Track`].
//! Slot heights, gridline colour, how overlapping things stack and which hour
//! scrolls into view stay the renderer's, and `Track` carries none of them.
//!
//! A kanban board is describable, and the member is [`Region::Columns`]. Every
//! card fact is already sayable through `Row`'s parts; what nothing else could
//! say is that the columns are *peers*, since [`Arrangement`] offers only
//! list-detail and sidebar-content and a board described as either is a lie
//! about the screen. Dragging a card between columns does not enter into it: a
//! drop's effect is "set status", a discrete action `Row`'s menu already
//! carries, and the drag itself is affordance.
//!
//! A calendar takes no members. The month grid's primacy in calendar apps is an
//! artifact of paper: paper cannot be queried, so it has to show every day at
//! once as a fallback index, and routes, search and ranking do that job better.
//! Three jobs survive that reasoning, and only one of them needs a grid:
//!
//! 1. **Spans across days**, a stretch of leave, a trip, a sprint. You cannot
//! see "away the 3rd to the 17th" in a list without diffing dates. This is
//! [`Track`] with [`Unit::Days`], and [`Track::days`] is it.
//! 2. **Density at a glance**, which weeks were heavy. That is a heatmap, and a
//! heatmap describes as a list.
//! 3. **Weekday periodicity**, "every other Tuesday", "the 15th is a Saturday".
//! This is the only job that needs the seven-column wrap, because alignment
//! is the whole of what makes it visible.
//!
//! Job 3 is the only open question, and nothing in the tree asks for it. A
//! month grid otherwise renders as a [`Table`](crate::Column): seven weekday
//! columns, weeks as rows, blanks for the offset. If a screen wants one,
//! measure the members it needs before adding any.
//!
//! [`Region::Handover`] and [`Region::Ceded`] remain for the genuinely
//! app-owned. The description
//! names the *place* and the app owns the contents, so a screen containing a
//! timeline is still a whole screen and still routable. Without it, the screens
//! that make an app worth using would need a second, undescribed path beside
//! the router, and two paths is how a vocabulary drifts from its app.
//!
//! [`Region::Widget`] sits between that limit and the primitives, and it does
//! not move the limit. A widget is an assembly of members this crate *already*
//! has, under a name a renderer may or may not recognise. Anything that needs a
//! member the vocabulary does not have is still a finding about the vocabulary
//! or still bespoke; naming an assembly buys no new expressive power, which is
//! why it is safe to let the set grow outside this crate.
/// A colour intent this crate refers to but never resolves.
///
/// The string is the token name `makeover` publishes, so a renderer can look
/// it up without this crate knowing what colour came back.
// The crate's entire API is these names at the root. Named rather than glob so
// a member added to a module and left out here fails at the first call site
// outside the crate instead of quietly leaving the root API.
pub use Act;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;