@stonedogcode/style 0.9.0 → 0.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/package.json
CHANGED
|
@@ -57,6 +57,28 @@ export interface StyledIconButtonProps extends HTMLStyledProps<"button"> {
|
|
|
57
57
|
rel?: string;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Props this component used to accept and no longer honours (NEH-498).
|
|
62
|
+
*
|
|
63
|
+
* They are dropped rather than forwarded because everything else in `rest` is
|
|
64
|
+
* spread onto the element: left alone, `confirm={true}` reaches the DOM as an
|
|
65
|
+
* invalid attribute and React warns about each one in the consumer's console.
|
|
66
|
+
* The doc above already promised these were ignored — this is what makes that
|
|
67
|
+
* true.
|
|
68
|
+
*
|
|
69
|
+
* This is a migration seam with an end date. Delete it once no consumer passes
|
|
70
|
+
* any of them; none does today, which is why they were removed in the first
|
|
71
|
+
* place.
|
|
72
|
+
*/
|
|
73
|
+
const REMOVED_PROPS = [
|
|
74
|
+
"confirm",
|
|
75
|
+
"confirmTitle",
|
|
76
|
+
"confirmBody",
|
|
77
|
+
"onConfirm",
|
|
78
|
+
"loading",
|
|
79
|
+
"noBackground",
|
|
80
|
+
] as const;
|
|
81
|
+
|
|
60
82
|
/** Map the full vocabulary onto what the recipe can actually paint. */
|
|
61
83
|
function toIconVariant(variant: AllowedVariant): IconButtonVariant {
|
|
62
84
|
if (variant === "unstyled") return "ghost";
|
|
@@ -92,6 +114,10 @@ const StyledIconButton = React.forwardRef<HTMLButtonElement, StyledIconButtonPro
|
|
|
92
114
|
// ignored.
|
|
93
115
|
const { zIndex, style, className: incoming, ...restWithoutZIndex } = rest;
|
|
94
116
|
|
|
117
|
+
for (const prop of REMOVED_PROPS) {
|
|
118
|
+
delete (restWithoutZIndex as Record<string, unknown>)[prop];
|
|
119
|
+
}
|
|
120
|
+
|
|
95
121
|
return (
|
|
96
122
|
<StyledTooltip tooltip={tooltip} placement={placement}>
|
|
97
123
|
<Element
|
|
@@ -32,6 +32,14 @@ import { useResolvedVariant } from "../config/style-config";
|
|
|
32
32
|
* radio rather than the group or the selection — reliably the wrong element.
|
|
33
33
|
* It now points at the group container. Nothing was using it.
|
|
34
34
|
*
|
|
35
|
+
* ## `onChange` is optional, and its absence means read-only (NEH-498)
|
|
36
|
+
*
|
|
37
|
+
* `checked` is always passed, so the inputs are controlled whether or not a
|
|
38
|
+
* handler is. Without one React reverts every click *and* warns once per radio
|
|
39
|
+
* in the consumer's console — a warning about nothing, which is the kind that
|
|
40
|
+
* teaches people to ignore the real ones. The inputs are marked `readOnly`
|
|
41
|
+
* instead, which is what the group actually is.
|
|
42
|
+
*
|
|
35
43
|
* The container is a plain `<div>` rather than `StyledBox`, which is what the
|
|
36
44
|
* original used. `StyledBox` wraps its children in an inner element unless told
|
|
37
45
|
* not to, and that element would sit between the `radiogroup` and its radios —
|
|
@@ -121,7 +129,10 @@ const StyledInputRadio = React.forwardRef<HTMLDivElement, StyledInputRadioProps>
|
|
|
121
129
|
value={radio.value}
|
|
122
130
|
checked={value === radio.value}
|
|
123
131
|
disabled={radio.disabled}
|
|
124
|
-
onChange
|
|
132
|
+
// A group with no `onChange` really is read-only — React reverts
|
|
133
|
+
// the click on a controlled input either way — so say so rather
|
|
134
|
+
// than leave React to warn about it in every consumer's console.
|
|
135
|
+
{...(onChange ? { onChange } : { readOnly: true })}
|
|
125
136
|
className={input}
|
|
126
137
|
/>
|
|
127
138
|
<div className={control}>
|
|
@@ -12,6 +12,33 @@ import { textRecipe } from "styled-system/recipes";
|
|
|
12
12
|
|
|
13
13
|
const PandaText = styled("span", textRecipe);
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* The spacing props that only a BLOCK box can honour.
|
|
17
|
+
*
|
|
18
|
+
* Horizontal spacing is deliberately absent. `margin-left` / `margin-right`
|
|
19
|
+
* work perfectly well on an inline box, and inline text inside a sentence is
|
|
20
|
+
* the commonest use of this component — promoting on those would break working
|
|
21
|
+
* layout to fix a different problem.
|
|
22
|
+
*/
|
|
23
|
+
const VERTICAL_SPACING_PROPS = [
|
|
24
|
+
"marginTop",
|
|
25
|
+
"marginBottom",
|
|
26
|
+
"marginBlock",
|
|
27
|
+
"marginBlockStart",
|
|
28
|
+
"marginBlockEnd",
|
|
29
|
+
"paddingTop",
|
|
30
|
+
"paddingBottom",
|
|
31
|
+
"paddingBlock",
|
|
32
|
+
"paddingBlockStart",
|
|
33
|
+
"paddingBlockEnd",
|
|
34
|
+
"mt",
|
|
35
|
+
"mb",
|
|
36
|
+
"my",
|
|
37
|
+
"pt",
|
|
38
|
+
"pb",
|
|
39
|
+
"py",
|
|
40
|
+
] as const;
|
|
41
|
+
|
|
15
42
|
export interface StyledTextProps
|
|
16
43
|
extends React.ComponentProps<typeof PandaText> {
|
|
17
44
|
children?: React.ReactNode | undefined;
|
|
@@ -24,9 +51,50 @@ export interface StyledTextProps
|
|
|
24
51
|
ellipsis?: boolean | undefined;
|
|
25
52
|
wrap?: boolean | undefined;
|
|
26
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Render as a block box rather than the default inline one.
|
|
56
|
+
*
|
|
57
|
+
* Set this when you want block flow without any spacing prop to trigger it —
|
|
58
|
+
* two paragraphs that should stack, for instance. A vertical margin or
|
|
59
|
+
* padding implies it already; see the note on the component.
|
|
60
|
+
*/
|
|
61
|
+
block?: boolean | undefined;
|
|
62
|
+
|
|
27
63
|
variant?: AllowedTextVariant | undefined;
|
|
28
64
|
}
|
|
29
65
|
|
|
66
|
+
/**
|
|
67
|
+
* `StyledText` renders a `<span>`, which is an INLINE box — and CSS ignores
|
|
68
|
+
* `margin-top` / `margin-bottom` on inline boxes outright.
|
|
69
|
+
*
|
|
70
|
+
* So `<StyledText marginBottom="1">` used to emit the rule, put the class in
|
|
71
|
+
* the DOM, report `margin-bottom: 8px` from `getComputedStyle`, and move
|
|
72
|
+
* nothing. Worse, JSX strips the whitespace between two elements on separate
|
|
73
|
+
* lines, so adjacent `StyledText` siblings rendered as a single run with no
|
|
74
|
+
* space at all — shipped in two products as "No dates to show yetThis does not
|
|
75
|
+
* mean nothing is due" and "OverviewYour Personal Dashboard" (NEH-490).
|
|
76
|
+
*
|
|
77
|
+
* **It worked in some places, which is what made it so hard to see.** Flex
|
|
78
|
+
* items are blockified, so a `StyledText` inside a `StyledStack` becomes a
|
|
79
|
+
* block and its margins apply; the identical component inside a `StyledBox`
|
|
80
|
+
* stays inline and breaks. Whoever adds the prop sees it work in the component
|
|
81
|
+
* they tested.
|
|
82
|
+
*
|
|
83
|
+
* So a vertical spacing prop promotes the box to `display: block`. This cannot
|
|
84
|
+
* break anything that currently works: on an inline box those declarations are
|
|
85
|
+
* already discarded, so nothing can be depending on their effect. The call
|
|
86
|
+
* sites were always right — the component was accepting a prop it could not
|
|
87
|
+
* honour and saying nothing.
|
|
88
|
+
*
|
|
89
|
+
* An explicit `display` from the caller always wins, and `block` is available
|
|
90
|
+
* for the case where you want block flow with no spacing prop to imply it.
|
|
91
|
+
*/
|
|
92
|
+
function wantsBlockBox(props: StyledTextProps): boolean {
|
|
93
|
+
if (props.block) return true;
|
|
94
|
+
const bag = props as unknown as Record<string, unknown>;
|
|
95
|
+
return VERTICAL_SPACING_PROPS.some((prop) => bag[prop] !== undefined);
|
|
96
|
+
}
|
|
97
|
+
|
|
30
98
|
const StyledText = React.forwardRef<HTMLSpanElement, StyledTextProps>((props, ref) => {
|
|
31
99
|
log.trace("StyledText rendered");
|
|
32
100
|
const {
|
|
@@ -41,6 +109,7 @@ const StyledText = React.forwardRef<HTMLSpanElement, StyledTextProps>((props, re
|
|
|
41
109
|
wrap,
|
|
42
110
|
textAlign,
|
|
43
111
|
className,
|
|
112
|
+
block: _block,
|
|
44
113
|
...rest
|
|
45
114
|
} = props;
|
|
46
115
|
const fontSizeProfile = useFontSizeProfile();
|
|
@@ -57,6 +126,12 @@ const StyledText = React.forwardRef<HTMLSpanElement, StyledTextProps>((props, re
|
|
|
57
126
|
const fontSize = fontSizeMap[finalSize] || fontSizeMap.md;
|
|
58
127
|
|
|
59
128
|
const extraStyles: React.CSSProperties = {};
|
|
129
|
+
// Before `ellipsis`, which sets its own `display: block` and must keep
|
|
130
|
+
// winning — an ellipsised line is block for a different reason and the two
|
|
131
|
+
// agree anyway.
|
|
132
|
+
if (wantsBlockBox(props)) {
|
|
133
|
+
extraStyles.display = "block";
|
|
134
|
+
}
|
|
60
135
|
if (ellipsis) {
|
|
61
136
|
extraStyles.textOverflow = "ellipsis";
|
|
62
137
|
extraStyles.whiteSpace = "nowrap";
|