@uniflowed/ui 0.0.0-alpha.18 → 0.0.0-alpha.37
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/accordion.js +61 -54
- package/alert-dialog.js +43 -17
- package/alert.js +142 -0
- package/avatar.js +276 -0
- package/breadcrumb.js +138 -0
- package/checkbox.js +45 -39
- package/collapsible.js +41 -36
- package/context-menu.js +32 -24
- package/dialog.js +143 -119
- package/drawer.js +121 -89
- package/field.js +71 -37
- package/hover-card.js +23 -27
- package/index.js +567 -31
- package/input-otp.js +8 -8
- package/interactions.js +2163 -0
- package/internal/merge-props.js +85 -1
- package/menu.js +236 -213
- package/menubar.js +91 -89
- package/package.json +8 -40
- package/pagination.js +29 -17
- package/popover.js +59 -55
- package/progress.js +21 -16
- package/radio-group.js +79 -75
- package/separator.js +97 -0
- package/sheet.js +41 -17
- package/sidebar.js +10 -10
- package/skeleton.js +159 -0
- package/slider.js +89 -89
- package/switch.js +37 -31
- package/table.js +90 -67
- package/tabs.js +100 -91
- package/toast.js +23 -55
- package/toggle-group.js +52 -49
- package/toggle.js +38 -25
- package/tooltip.js +26 -37
package/internal/merge-props.js
CHANGED
|
@@ -20,6 +20,16 @@
|
|
|
20
20
|
// a caller legitimately wants *both* — event handlers and refs — they are
|
|
21
21
|
// composed rather than one replacing the other.
|
|
22
22
|
//
|
|
23
|
+
// # The other half of the rule: which element the props land on
|
|
24
|
+
//
|
|
25
|
+
// Everything above decides what goes onto the element. `RenderProp` is what
|
|
26
|
+
// decides *which element*, and it is here rather than in a module of its own
|
|
27
|
+
// because it is the same policy read from the other end: a part computes one
|
|
28
|
+
// props object, and either puts it on the element it would have chosen or hands
|
|
29
|
+
// it to the caller to put on theirs. Two ways of composing a caller's props
|
|
30
|
+
// would be two chances to get the order wrong; one shape, stated once, is what
|
|
31
|
+
// keeps a part that renders somebody else's element from being a weaker part.
|
|
32
|
+
//
|
|
23
33
|
// # Why this is `internal/` and not a subpath
|
|
24
34
|
//
|
|
25
35
|
// It is not a "props utils" module and there is nothing else in it. It is the
|
|
@@ -28,6 +38,8 @@
|
|
|
28
38
|
// consumer to build a part that spreads `rest` last, which is the failure this
|
|
29
39
|
// exists to prevent — so it stays unreachable from outside the package.
|
|
30
40
|
|
|
41
|
+
import type { Node } from "@uniflowed/react";
|
|
42
|
+
|
|
31
43
|
/**
|
|
32
44
|
* Props on their way onto an element: what a caller hands a part, and what
|
|
33
45
|
* `Field.Control` hands back for a caller to spread.
|
|
@@ -75,6 +87,78 @@
|
|
|
75
87
|
*/
|
|
76
88
|
export type Rest = { readonly key?: empty, readonly [string]: mixed };
|
|
77
89
|
|
|
90
|
+
/**
|
|
91
|
+
* The escape hatch: a caller's element in place of the part's own.
|
|
92
|
+
*
|
|
93
|
+
* `@uniflowed/ui` has no copy step — `packages/ui/index.js`'s header argues
|
|
94
|
+
* that at length — and the thing a copy step is *for* is changing the markup. A
|
|
95
|
+
* part that always renders a `<button>` cannot be the link a menu of links
|
|
96
|
+
* needs; a heading fixed at `<h2>` is wrong inside an accordion. This is what
|
|
97
|
+
* replaces owning the source: the part still computes every attribute, every
|
|
98
|
+
* composed handler and every id, and hands them to the caller to put on
|
|
99
|
+
* whatever element they wanted.
|
|
100
|
+
*
|
|
101
|
+
* One name and one signature everywhere, which is the point. `asChild` clones a
|
|
102
|
+
* child and hopes its props survive; this hands the props over explicitly, so a
|
|
103
|
+
* caller can see what they are getting, decide the order themselves, and drop
|
|
104
|
+
* one deliberately. The part is still the part — `Menu.Body`'s `renders*` still
|
|
105
|
+
* rejects a `<div>` where a `Menu.Item` belongs, because the escape hatch
|
|
106
|
+
* changes the element the item renders and not what the item *is*. That
|
|
107
|
+
* constraint is exactly what a copied source loses.
|
|
108
|
+
*
|
|
109
|
+
* # What is in the props, and what is not
|
|
110
|
+
*
|
|
111
|
+
* Everything the part would have put on its own element, in the order
|
|
112
|
+
* `withProps` fixes: the caller's `rest` underneath, the part's own semantics on
|
|
113
|
+
* top, handlers and refs composed rather than replaced. `children` is in there
|
|
114
|
+
* too, so `render={(props) => <a href={to} {...props} />}` renders what was
|
|
115
|
+
* written between the tags — a part whose children were silently dropped
|
|
116
|
+
* because the caller spread the props and forgot them is the kind of quiet
|
|
117
|
+
* wrongness this package exists to not have. JSX children win over a spread, so
|
|
118
|
+
* `<a {...props}>Other</a>` still says what it says.
|
|
119
|
+
*
|
|
120
|
+
* What is *not* in there is anything true of the element rather than of the
|
|
121
|
+
* part: `type="button"` is the only one in practice, and it stays on the
|
|
122
|
+
* `<button>` branch. Handing it to a caller rendering an `<a>` would put an
|
|
123
|
+
* attribute the HTML has no meaning for on their link.
|
|
124
|
+
*/
|
|
125
|
+
export type RenderProp = (props: Rest) => Node;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* What a part's own handler reads of the event it is handed.
|
|
129
|
+
*
|
|
130
|
+
* Inexact, and named rather than inferred, for the same reason `menu.js`'s
|
|
131
|
+
* `MenuSelect` is: what arrives is React's synthetic event, uf does not merge
|
|
132
|
+
* Flow's `jsx.js` environment so `lib/react.js` models no such thing, and these
|
|
133
|
+
* are the members the handlers in this package actually read.
|
|
134
|
+
*
|
|
135
|
+
* It exists because of `RenderProp`. A handler written inside a JSX attribute
|
|
136
|
+
* gets its parameter's type from the attribute, which for an intrinsic is
|
|
137
|
+
* `any`; the escape hatch has to build the props *before* there is an element
|
|
138
|
+
* to put them on, so the same handler in an object literal has an indexer's
|
|
139
|
+
* `mixed` for context and Flow asks for an annotation. This is that annotation,
|
|
140
|
+
* written once rather than at every handler in the package.
|
|
141
|
+
*
|
|
142
|
+
* One shape for keys and for presses, which is the one thing it is not honest
|
|
143
|
+
* about: `key` and the modifiers belong to a keyboard event and a click has no
|
|
144
|
+
* `key`. It is a parameter annotation for handlers this package writes rather
|
|
145
|
+
* than a description of an event, nothing widens `mixed` into it, and the day
|
|
146
|
+
* `$JSXIntrinsics` is real — the day `Rest` becomes `React.PropsOf`, which its
|
|
147
|
+
* own comment is waiting for — is the day this is React's event types instead.
|
|
148
|
+
*/
|
|
149
|
+
export type PartEvent = {
|
|
150
|
+
readonly defaultPrevented: boolean,
|
|
151
|
+
readonly key: string,
|
|
152
|
+
readonly altKey: boolean,
|
|
153
|
+
readonly ctrlKey: boolean,
|
|
154
|
+
readonly metaKey: boolean,
|
|
155
|
+
readonly shiftKey: boolean,
|
|
156
|
+
readonly currentTarget: mixed,
|
|
157
|
+
readonly preventDefault: () => mixed,
|
|
158
|
+
readonly stopPropagation: () => mixed,
|
|
159
|
+
...
|
|
160
|
+
};
|
|
161
|
+
|
|
78
162
|
/**
|
|
79
163
|
* A caller's props on their way to another *part of this package*, rather than
|
|
80
164
|
* onto an intrinsic element.
|
|
@@ -116,7 +200,7 @@ export function forwarded(rest: Rest): $FlowFixMe {
|
|
|
116
200
|
* `defaultPrevented` is the caller's way of saying "I handled this", which is
|
|
117
201
|
* the same contract the DOM uses.
|
|
118
202
|
*/
|
|
119
|
-
export function composeHandlers<TEvent extends { readonly defaultPrevented?: boolean }>(
|
|
203
|
+
export function composeHandlers<TEvent extends { readonly defaultPrevented?: boolean, ... }>(
|
|
120
204
|
theirs: mixed,
|
|
121
205
|
ours: (event: TEvent) => mixed,
|
|
122
206
|
): (event: TEvent) => mixed {
|