@signal9/era-ui 4.16.9 → 6.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/dist/dev/audit/audits/even-container-padding.d.ts +2 -0
- package/dist/dev/audit/audits/even-container-padding.js +62 -0
- package/dist/dev/audit/audits/index.d.ts +2 -1
- package/dist/dev/audit/audits/index.js +3 -1
- package/dist/era-ui.css +1 -1
- package/dist/generated-docs/llms-full.txt +35 -26
- package/dist/generated-docs/llms.txt +5 -1
- package/dist/generated-docs/manifest.json +7 -6
- package/dist/generated-docs/utilities.json +5 -4
- package/dist/generated-docs/utilities.md +39 -30
- package/dist/styles/index.css +38 -0
- package/dist/styles/typography.css +28 -11
- package/dist/ui/badge/badge.svelte +9 -1
- package/dist/ui/badge/badge.svelte.d.ts +1 -1
- package/dist/ui/card/card.svelte +16 -6
- package/dist/ui/card/card.svelte.d.ts +3 -3
- package/dist/ui/kv/kv.svelte +6 -1
- package/package.json +2 -1
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* A box's content sits the same distance from its top edge as from its bottom.
|
|
3
|
+
*
|
|
4
|
+
* The even-gap law, stated for the containers the tier checks cannot see. The
|
|
5
|
+
* radius/height audits only apply to BOUNDED tier controls (a button in a bar),
|
|
6
|
+
* because their identity needs a height term. An unbounded container — a card,
|
|
7
|
+
* a panel, a popover body — has no tier, so nothing checked it at all, and the
|
|
8
|
+
* Card component shipped for weeks with half-height top padding: content 4px
|
|
9
|
+
* from the top edge against 8px from the bottom, on every card in every
|
|
10
|
+
* consumer app. It was reported from the outside as "cards aren't evenly
|
|
11
|
+
* spaced", which is precisely what it was.
|
|
12
|
+
*
|
|
13
|
+
* The rule is vertical only. Horizontal asymmetry is often correct and
|
|
14
|
+
* deliberate in era — a pane handle's leading side sits at the text inset while
|
|
15
|
+
* its trailing side keeps the concentric wall, a code block reserves room for
|
|
16
|
+
* its copy button — so flagging it would be noise. Nothing has a reason to sit
|
|
17
|
+
* closer to its top edge than its bottom.
|
|
18
|
+
*
|
|
19
|
+
* `p-content` is the one earned exception and is exempt by construction rather
|
|
20
|
+
* than by name: it subtracts the heading ROW's own slack from its top padding,
|
|
21
|
+
* so it only ever appears on a full-bleed section with no radius, and this
|
|
22
|
+
* audit looks only at rounded boxes — the ones that read as a container.
|
|
23
|
+
*/
|
|
24
|
+
/** Below this, a box is a hairline or a divider, not a container. */
|
|
25
|
+
const MIN_BOX = 8;
|
|
26
|
+
export const evenContainerPadding = {
|
|
27
|
+
id: 'layout/even-container-padding',
|
|
28
|
+
name: 'Container padding is vertically even',
|
|
29
|
+
description: 'A rounded container must pad its content equally at top and bottom — content closer to one edge than the other breaks the even-gap law on the surfaces that bound the most consumer content.',
|
|
30
|
+
category: 'layout',
|
|
31
|
+
severity: 'warn',
|
|
32
|
+
selector: '*',
|
|
33
|
+
check(el) {
|
|
34
|
+
const s = getComputedStyle(el);
|
|
35
|
+
// Rounded boxes only: a radius is what makes a box read as a container
|
|
36
|
+
// with edges, and it also excludes the full-bleed page sections whose
|
|
37
|
+
// top padding is legitimately reduced (see p-content).
|
|
38
|
+
if (parseFloat(s.borderTopLeftRadius) <= 0)
|
|
39
|
+
return null;
|
|
40
|
+
const top = parseFloat(s.paddingTop) || 0;
|
|
41
|
+
const bottom = parseFloat(s.paddingBottom) || 0;
|
|
42
|
+
if (top === bottom)
|
|
43
|
+
return null;
|
|
44
|
+
// A container pads BOTH sides or neither; one-sided padding is a spacer,
|
|
45
|
+
// not a container's inset.
|
|
46
|
+
if (top === 0 || bottom === 0)
|
|
47
|
+
return null;
|
|
48
|
+
const rect = el.getBoundingClientRect();
|
|
49
|
+
if (rect.height < MIN_BOX || rect.width < MIN_BOX)
|
|
50
|
+
return null;
|
|
51
|
+
// Sub-pixel drift from a calc() is not a design error.
|
|
52
|
+
if (Math.abs(top - bottom) < 0.51)
|
|
53
|
+
return null;
|
|
54
|
+
const issue = {
|
|
55
|
+
auditId: 'layout/even-container-padding',
|
|
56
|
+
element: el,
|
|
57
|
+
message: `padding-top ${top.toFixed(1)} ≠ padding-bottom ${bottom.toFixed(1)} — content sits ${top < bottom ? 'high' : 'low'} in its container. Pad evenly (p-card / p-panel), or drop the radius if this is a full-bleed section.`,
|
|
58
|
+
details: { top, bottom, delta: +(top - bottom).toFixed(2) }
|
|
59
|
+
};
|
|
60
|
+
return issue;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
@@ -2,6 +2,7 @@ import { clippedGlyphs } from './clipped-glyphs.js';
|
|
|
2
2
|
import { collapsedTextTrim } from './collapsed-text-trim.js';
|
|
3
3
|
import { concentricInset } from './concentric-inset.js';
|
|
4
4
|
import { cornersAxis } from './corners-axis.js';
|
|
5
|
+
import { evenContainerPadding } from './even-container-padding.js';
|
|
5
6
|
import { flatChrome } from './flat-chrome.js';
|
|
6
7
|
import { iconFlush } from './icon-flush.js';
|
|
7
8
|
import { offAxisMotion } from './off-axis-motion.js';
|
|
@@ -13,4 +14,4 @@ import { restingGap } from './resting-gap.js';
|
|
|
13
14
|
import { singleGlyphSquare } from './single-glyph-square.js';
|
|
14
15
|
import { uniformSiblingGaps } from './uniform-sibling-gaps.js';
|
|
15
16
|
import { wallMatchesGap } from './wall-matches-gap.js';
|
|
16
|
-
export { clippedGlyphs, collapsedTextTrim, concentricInset, cornersAxis, flatChrome, iconFlush, offAxisMotion, offTierHeight, pillHoldsItsInk, proseLeading, radiusConcentricity, restingGap, singleGlyphSquare, uniformSiblingGaps, wallMatchesGap };
|
|
17
|
+
export { clippedGlyphs, collapsedTextTrim, concentricInset, cornersAxis, evenContainerPadding, flatChrome, iconFlush, offAxisMotion, offTierHeight, pillHoldsItsInk, proseLeading, radiusConcentricity, restingGap, singleGlyphSquare, uniformSiblingGaps, wallMatchesGap };
|
|
@@ -3,6 +3,7 @@ import { clippedGlyphs } from './clipped-glyphs.js';
|
|
|
3
3
|
import { collapsedTextTrim } from './collapsed-text-trim.js';
|
|
4
4
|
import { concentricInset } from './concentric-inset.js';
|
|
5
5
|
import { cornersAxis } from './corners-axis.js';
|
|
6
|
+
import { evenContainerPadding } from './even-container-padding.js';
|
|
6
7
|
import { flatChrome } from './flat-chrome.js';
|
|
7
8
|
import { iconFlush } from './icon-flush.js';
|
|
8
9
|
import { offAxisMotion } from './off-axis-motion.js';
|
|
@@ -14,7 +15,7 @@ import { restingGap } from './resting-gap.js';
|
|
|
14
15
|
import { singleGlyphSquare } from './single-glyph-square.js';
|
|
15
16
|
import { uniformSiblingGaps } from './uniform-sibling-gaps.js';
|
|
16
17
|
import { wallMatchesGap } from './wall-matches-gap.js';
|
|
17
|
-
export { clippedGlyphs, collapsedTextTrim, concentricInset, cornersAxis, flatChrome, iconFlush, offAxisMotion, offTierHeight, pillHoldsItsInk, proseLeading, radiusConcentricity, restingGap, singleGlyphSquare, uniformSiblingGaps, wallMatchesGap };
|
|
18
|
+
export { clippedGlyphs, collapsedTextTrim, concentricInset, cornersAxis, evenContainerPadding, flatChrome, iconFlush, offAxisMotion, offTierHeight, pillHoldsItsInk, proseLeading, radiusConcentricity, restingGap, singleGlyphSquare, uniformSiblingGaps, wallMatchesGap };
|
|
18
19
|
// Auto-register built-ins. Consumers can still unregister or add their own.
|
|
19
20
|
//
|
|
20
21
|
// Two of these only tell the truth on a particular axis setting, because the bug
|
|
@@ -27,6 +28,7 @@ registry.register(clippedGlyphs);
|
|
|
27
28
|
registry.register(collapsedTextTrim);
|
|
28
29
|
registry.register(concentricInset);
|
|
29
30
|
registry.register(cornersAxis);
|
|
31
|
+
registry.register(evenContainerPadding);
|
|
30
32
|
registry.register(flatChrome);
|
|
31
33
|
registry.register(iconFlush);
|
|
32
34
|
registry.register(offAxisMotion);
|