@tonycodes-ui/mortar 0.12.0 → 0.13.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/CHANGELOG.md +16 -39
- package/DESIGN.md +1 -1
- package/catalog.json +413 -377
- package/cli/audit.mjs +152 -0
- package/dist/agent-data.json +1 -1
- package/dist/application.d.ts +30 -5
- package/dist/application.js +20 -8
- package/dist/index.d.ts +1 -1
- package/dist/inspection.js +17 -1
- package/dist/internal.d.ts +15 -1
- package/dist/internal.js +12 -1
- package/dist/marketing.d.ts +3 -2
- package/dist/marketing.js +2 -6
- package/dist/primitives.js +20 -11
- package/docs/agents.md +21 -18
- package/docs/theming.md +72 -1
- package/package.json +1 -1
- package/skills/mortar/SKILL.md +1 -1
- package/src/application.css +95 -1
- package/src/application.tsx +88 -19
- package/src/data.css +58 -2
- package/src/foundation.css +10 -0
- package/src/index.ts +3 -0
- package/src/inspection.tsx +15 -0
- package/src/internal.tsx +93 -2
- package/src/marketing.tsx +4 -74
- package/src/primitives.tsx +38 -19
package/src/marketing.tsx
CHANGED
|
@@ -3,17 +3,9 @@ import {
|
|
|
3
3
|
KitLink,
|
|
4
4
|
type IconLink,
|
|
5
5
|
type ItemGroup,
|
|
6
|
-
type LinkItem,
|
|
7
6
|
} from "./navigation.js";
|
|
8
7
|
import { useId, useState, type CSSProperties, type ReactNode } from "react";
|
|
9
|
-
import {
|
|
10
|
-
CloseButton,
|
|
11
|
-
DialogPanel,
|
|
12
|
-
DialogTitle,
|
|
13
|
-
Popover,
|
|
14
|
-
PopoverButton,
|
|
15
|
-
PopoverPanel,
|
|
16
|
-
} from "@headlessui/react";
|
|
8
|
+
import { DialogPanel, DialogTitle } from "@headlessui/react";
|
|
17
9
|
import { ActionLink, Button, type LinkAction } from "./primitives.js";
|
|
18
10
|
import { BrandMark, Prose, type SectionTone } from "./layout.js";
|
|
19
11
|
import { SegmentedControl } from "./inspection.js";
|
|
@@ -23,6 +15,8 @@ import { childLevel, headingTag, type HeadingLevel } from "./heading.js";
|
|
|
23
15
|
import {
|
|
24
16
|
ActionLinks,
|
|
25
17
|
DialogFrame,
|
|
18
|
+
Flyout,
|
|
19
|
+
type FlyoutItem,
|
|
26
20
|
TermList,
|
|
27
21
|
TitledIntro,
|
|
28
22
|
cx,
|
|
@@ -32,10 +26,7 @@ import {
|
|
|
32
26
|
useDomId,
|
|
33
27
|
} from "./internal.js";
|
|
34
28
|
|
|
35
|
-
export type FlyoutItem
|
|
36
|
-
LinkItem,
|
|
37
|
-
"label" | "href" | "description" | "icon"
|
|
38
|
-
>;
|
|
29
|
+
export type { FlyoutItem } from "./internal.js";
|
|
39
30
|
/** A header link, or a labelled group that opens a flyout panel. */
|
|
40
31
|
export type HeaderLink =
|
|
41
32
|
| LinkAction
|
|
@@ -45,67 +36,6 @@ export type HeaderLink =
|
|
|
45
36
|
layout?: "list" | "columns" | "full";
|
|
46
37
|
});
|
|
47
38
|
|
|
48
|
-
function Flyout({
|
|
49
|
-
label,
|
|
50
|
-
items,
|
|
51
|
-
footer = [],
|
|
52
|
-
layout = "list",
|
|
53
|
-
onNavigate,
|
|
54
|
-
}: {
|
|
55
|
-
label: string;
|
|
56
|
-
items: FlyoutItem[];
|
|
57
|
-
footer?: LinkAction[];
|
|
58
|
-
layout?: "list" | "columns" | "full";
|
|
59
|
-
onNavigate: () => void;
|
|
60
|
-
}) {
|
|
61
|
-
const dataLayout = layout === "list" ? undefined : layout;
|
|
62
|
-
return (
|
|
63
|
-
<Popover className="m-flyout" data-layout={dataLayout}>
|
|
64
|
-
<PopoverButton className="m-flyout-trigger">
|
|
65
|
-
{label}
|
|
66
|
-
<ChevronDown />
|
|
67
|
-
</PopoverButton>
|
|
68
|
-
{/* Anchored panels render in a portal, so headers inside clipped containers never cut them off. */}
|
|
69
|
-
<PopoverPanel
|
|
70
|
-
anchor="bottom"
|
|
71
|
-
className="m-flyout-panel"
|
|
72
|
-
data-layout={dataLayout}
|
|
73
|
-
>
|
|
74
|
-
<ul>
|
|
75
|
-
{items.map((item, index) => (
|
|
76
|
-
<li key={`${item.label}:${item.href}:${index}`}>
|
|
77
|
-
<CloseButton as={KitLink} href={item.href} onClick={onNavigate}>
|
|
78
|
-
{item.icon && (
|
|
79
|
-
<span className="m-flyout-icon" aria-hidden="true">
|
|
80
|
-
{item.icon}
|
|
81
|
-
</span>
|
|
82
|
-
)}
|
|
83
|
-
<span className="m-flyout-text">
|
|
84
|
-
<strong>{item.label}</strong>
|
|
85
|
-
{item.description && <span>{item.description}</span>}
|
|
86
|
-
</span>
|
|
87
|
-
</CloseButton>
|
|
88
|
-
</li>
|
|
89
|
-
))}
|
|
90
|
-
</ul>
|
|
91
|
-
{footer.length > 0 && (
|
|
92
|
-
<div className="m-flyout-footer">
|
|
93
|
-
{footer.map((link, index) => (
|
|
94
|
-
<CloseButton
|
|
95
|
-
as={KitLink}
|
|
96
|
-
key={`${link.label}:${link.href}:${index}`}
|
|
97
|
-
href={link.href}
|
|
98
|
-
onClick={onNavigate}
|
|
99
|
-
>
|
|
100
|
-
{link.label}
|
|
101
|
-
</CloseButton>
|
|
102
|
-
))}
|
|
103
|
-
</div>
|
|
104
|
-
)}
|
|
105
|
-
</PopoverPanel>
|
|
106
|
-
</Popover>
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
39
|
export function MarketingHeader({
|
|
110
40
|
brand,
|
|
111
41
|
tagline,
|
package/src/primitives.tsx
CHANGED
|
@@ -444,6 +444,31 @@ function DescribedChoice({
|
|
|
444
444
|
</div>
|
|
445
445
|
);
|
|
446
446
|
}
|
|
447
|
+
/**
|
|
448
|
+
* Keeps a choice in the described layout once it has had a description or
|
|
449
|
+
* error. Switching back to the plain label would remount the input and drop
|
|
450
|
+
* focus mid-interaction (for example a description that changes with the
|
|
451
|
+
* value). If the layout changes while the input has focus, focus follows it.
|
|
452
|
+
*/
|
|
453
|
+
function useDescribedLayout(
|
|
454
|
+
active: boolean,
|
|
455
|
+
input: { current: HTMLInputElement | null },
|
|
456
|
+
) {
|
|
457
|
+
const [described, setDescribed] = useState(false);
|
|
458
|
+
const refocus = useRef(false);
|
|
459
|
+
if (active && !described) {
|
|
460
|
+
refocus.current =
|
|
461
|
+
typeof document !== "undefined" &&
|
|
462
|
+
!!input.current &&
|
|
463
|
+
input.current === document.activeElement;
|
|
464
|
+
setDescribed(true);
|
|
465
|
+
}
|
|
466
|
+
useLayoutEffect(() => {
|
|
467
|
+
if (refocus.current) input.current?.focus();
|
|
468
|
+
refocus.current = false;
|
|
469
|
+
}, [described, input]);
|
|
470
|
+
return described;
|
|
471
|
+
}
|
|
447
472
|
export function Checkbox({
|
|
448
473
|
label,
|
|
449
474
|
description,
|
|
@@ -458,23 +483,8 @@ export function Checkbox({
|
|
|
458
483
|
error?: string;
|
|
459
484
|
}) {
|
|
460
485
|
const input = useRef<HTMLInputElement>(null);
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
// it. If the layout changes while the input has focus, focus follows it.
|
|
464
|
-
const [described, setDescribed] = useState(false);
|
|
465
|
-
const refocus = useRef(false);
|
|
466
|
-
if (error && !described) {
|
|
467
|
-
refocus.current =
|
|
468
|
-
typeof document !== "undefined" &&
|
|
469
|
-
!!input.current &&
|
|
470
|
-
input.current === document.activeElement;
|
|
471
|
-
setDescribed(true);
|
|
472
|
-
}
|
|
473
|
-
useLayoutEffect(() => {
|
|
474
|
-
if (refocus.current) input.current?.focus();
|
|
475
|
-
refocus.current = false;
|
|
476
|
-
}, [described]);
|
|
477
|
-
if (description || error || described)
|
|
486
|
+
const described = useDescribedLayout(!!(description || error), input);
|
|
487
|
+
if (described)
|
|
478
488
|
return (
|
|
479
489
|
<DescribedChoice
|
|
480
490
|
component="Checkbox"
|
|
@@ -514,7 +524,9 @@ export function Switch({
|
|
|
514
524
|
/** Secondary line under the label, announced as the description. */
|
|
515
525
|
description?: ReactNode;
|
|
516
526
|
}) {
|
|
517
|
-
|
|
527
|
+
const input = useRef<HTMLInputElement>(null);
|
|
528
|
+
const described = useDescribedLayout(!!description, input);
|
|
529
|
+
if (described)
|
|
518
530
|
return (
|
|
519
531
|
<DescribedChoice
|
|
520
532
|
component="Switch"
|
|
@@ -526,6 +538,7 @@ export function Switch({
|
|
|
526
538
|
<input
|
|
527
539
|
{...props}
|
|
528
540
|
{...attrs}
|
|
541
|
+
ref={input}
|
|
529
542
|
type="checkbox"
|
|
530
543
|
role="switch"
|
|
531
544
|
className="m-switch"
|
|
@@ -535,7 +548,13 @@ export function Switch({
|
|
|
535
548
|
);
|
|
536
549
|
return (
|
|
537
550
|
<label {...componentRoot("Switch")} className={cx("m-choice", className)}>
|
|
538
|
-
<input
|
|
551
|
+
<input
|
|
552
|
+
{...props}
|
|
553
|
+
ref={input}
|
|
554
|
+
type="checkbox"
|
|
555
|
+
role="switch"
|
|
556
|
+
className="m-switch"
|
|
557
|
+
/>
|
|
539
558
|
{label}
|
|
540
559
|
</label>
|
|
541
560
|
);
|