@cueplusplus/ui 0.1.0 → 0.2.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 +684 -0
- package/dist/brand/_chassis.d.ts +54 -0
- package/dist/brand/_chassis.js +81 -0
- package/dist/brand/_geometry.js +41 -0
- package/dist/brand/cue-logotype.d.ts +29 -0
- package/dist/brand/cue-logotype.js +60 -0
- package/dist/brand/cue-mark.d.ts +30 -0
- package/dist/brand/cue-mark.js +61 -0
- package/dist/brand/index.d.ts +5 -0
- package/dist/brand/plussie.d.ts +67 -0
- package/dist/brand/plussie.js +125 -0
- package/dist/chat/agent-pile.js +1 -1
- package/dist/chat/ask-box.js +2 -2
- package/dist/chat/delegation-card.js +1 -1
- package/dist/chat/message.js +2 -2
- package/dist/chrome/_edge-scroller.d.ts +45 -0
- package/dist/chrome/_edge-scroller.js +138 -0
- package/dist/chrome/_glyphs.js +19 -1
- package/dist/chrome/_tabs-scroll.d.ts +12 -7
- package/dist/chrome/_tabs-scroll.js +12 -7
- package/dist/chrome/app-bar.d.ts +103 -0
- package/dist/chrome/app-bar.js +175 -0
- package/dist/chrome/app-shell.d.ts +125 -0
- package/dist/chrome/app-shell.js +167 -0
- package/dist/chrome/footer.d.ts +75 -0
- package/dist/chrome/footer.js +68 -0
- package/dist/chrome/index.d.ts +5 -1
- package/dist/chrome/index.js +4 -1
- package/dist/chrome/navigation-menu.js +1 -1
- package/dist/chrome/page-shell.d.ts +1 -1
- package/dist/chrome/page-shell.js +15 -5
- package/dist/chrome/segmented-control.d.ts +19 -0
- package/dist/chrome/segmented-control.js +40 -21
- package/dist/chrome/tabs.js +21 -65
- package/dist/chrome/toolbar.d.ts +22 -0
- package/dist/chrome/toolbar.js +26 -5
- package/dist/configurator/_overrides.js +4 -2
- package/dist/configurator/configurator.js +1 -1
- package/dist/configurator/panel-sections.js +10 -4
- package/dist/dmx/channel-matrix.js +1 -1
- package/dist/forms/otp-field.js +1 -1
- package/dist/index.d.ts +15 -6
- package/dist/index.js +15 -9
- package/dist/instruments/data-table.js +1 -1
- package/dist/layout/carousel.js +1 -1
- package/dist/layout/container.d.ts +1 -1
- package/dist/layout/container.js +6 -3
- package/dist/layout/index.d.ts +3 -3
- package/dist/layout/index.js +3 -3
- package/dist/layout/pagination.js +1 -1
- package/dist/layout/sidebar.d.ts +23 -3
- package/dist/layout/sidebar.js +18 -7
- package/dist/midi/spectrum-visualizer.js +1 -1
- package/dist/midi/timeline-ruler.js +1 -1
- package/dist/overlays/command-palette.js +1 -1
- package/dist/overlays/dialog.js +1 -1
- package/dist/overlays/dropdown-menu.js +2 -2
- package/dist/overlays/hover-card.js +1 -1
- package/dist/overlays/index.js +1 -1
- package/dist/overlays/popover.js +1 -1
- package/dist/overlays/sheet.js +1 -1
- package/dist/overlays/toast.js +1 -1
- package/dist/primitives/index.d.ts +1 -1
- package/dist/primitives/index.js +1 -1
- package/dist/primitives/status-dot.d.ts +7 -0
- package/dist/primitives/status-dot.js +8 -1
- package/dist/styles.css +47 -1
- package/dist/system/density.d.ts +4 -1
- package/dist/system/density.js +12 -4
- package/dist/system/index.d.ts +2 -2
- package/dist/system/portal.d.ts +5 -5
- package/dist/system/portal.js +11 -6
- package/dist/system/prepaint.d.ts +15 -8
- package/dist/system/prepaint.js +26 -9
- package/dist/system/theme-provider.d.ts +36 -10
- package/dist/system/theme-provider.js +56 -18
- package/dist/system/use-density.d.ts +3 -3
- package/dist/system/use-density.js +16 -6
- package/dist/system/use-theme.d.ts +4 -2
- package/dist/system/use-theme.js +4 -2
- package/dist/theming/_presets.js +80 -5
- package/dist/theming/create-theme.js +13 -4
- package/package.json +4 -3
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
//#region src/brand/_chassis.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* What every brand asset in this group shares: how big it is drawn, where its
|
|
5
|
+
* ink comes from, and how it is named to a screen reader.
|
|
6
|
+
*
|
|
7
|
+
* Three assets, one contract, because a header that puts the mark next to the
|
|
8
|
+
* logotype has to be able to say `size="sm"` twice and get two things the same
|
|
9
|
+
* height.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Rung of the density control ladder a brand asset is drawn at.
|
|
13
|
+
*
|
|
14
|
+
* The same three rungs `Button`, `Avatar` and every form control use, and for
|
|
15
|
+
* the same reason: a mark in a toolbar is furniture on that toolbar's row, so
|
|
16
|
+
* it has to move when the density does. `size` picks the rung; the density
|
|
17
|
+
* decides what the rung measures.
|
|
18
|
+
*/
|
|
19
|
+
type BrandSize = "sm" | "md" | "lg";
|
|
20
|
+
/**
|
|
21
|
+
* Where a brand asset takes its ink from.
|
|
22
|
+
*
|
|
23
|
+
* Not a light/dark pair. The source artwork ships two files that hard-code
|
|
24
|
+
* `white`, `black` and `#1E1E1E`; this library ships one component that reads
|
|
25
|
+
* the token layer, so a single element is correct in all eight presets and both
|
|
26
|
+
* modes without anybody choosing a file.
|
|
27
|
+
*/
|
|
28
|
+
type BrandTone = "inherit" | "fg" | "accent";
|
|
29
|
+
/** The props every asset in this group takes. */
|
|
30
|
+
interface BrandAssetProps extends Omit<React.ComponentPropsWithoutRef<"svg">, "children" | "width" | "height" | "title"> {
|
|
31
|
+
/**
|
|
32
|
+
* Rung of the density control ladder to draw at, or an explicit height in px.
|
|
33
|
+
* Defaults to `"md"`.
|
|
34
|
+
*
|
|
35
|
+
* Height, always — every asset here keeps its own aspect ratio, so the width
|
|
36
|
+
* follows from the artwork rather than from the caller.
|
|
37
|
+
*/
|
|
38
|
+
size?: BrandSize | number;
|
|
39
|
+
/**
|
|
40
|
+
* Where the ink comes from: `currentColor`, the foreground token, or the
|
|
41
|
+
* accent. Defaults to `"inherit"`.
|
|
42
|
+
*/
|
|
43
|
+
tone?: BrandTone;
|
|
44
|
+
/**
|
|
45
|
+
* The accessible name.
|
|
46
|
+
*
|
|
47
|
+
* Omit it and the asset is decorative — `aria-hidden`, announced by nothing.
|
|
48
|
+
* Pass one only when the mark is the *only* thing naming what it sits on: a
|
|
49
|
+
* bare logo link, a splash screen with no heading.
|
|
50
|
+
*/
|
|
51
|
+
title?: string;
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { BrandAssetProps, BrandSize, BrandTone };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
//#region src/brand/_chassis.ts
|
|
2
|
+
/** The heights of the three rungs, straight off the density ladder. */
|
|
3
|
+
const RUNG_HEIGHTS = {
|
|
4
|
+
sm: "var(--cue-control-sm)",
|
|
5
|
+
md: "var(--cue-control-md)",
|
|
6
|
+
lg: "var(--cue-control-lg)"
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* The height a `size` resolves to, as a CSS length.
|
|
10
|
+
*
|
|
11
|
+
* A rung name reads the token, so the asset tracks the density island it is
|
|
12
|
+
* in. A number is an explicit height in px at the default 16px root, emitted as
|
|
13
|
+
* `rem` so it tracks browser zoom instead — the same escape hatch, and the same
|
|
14
|
+
* conversion, `StatusDot` gives its diameter.
|
|
15
|
+
*
|
|
16
|
+
* @param size A rung of the ladder, or a height in px.
|
|
17
|
+
*/
|
|
18
|
+
function brandHeight(size) {
|
|
19
|
+
return typeof size === "number" ? `${size / 16}rem` : RUNG_HEIGHTS[size];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The width a `size` resolves to for an asset that is not square.
|
|
23
|
+
*
|
|
24
|
+
* A rung stays symbolic — `calc()` over the token, so the width still moves
|
|
25
|
+
* when the density does. An explicit height is a number here and now, so it is
|
|
26
|
+
* multiplied out rather than left as arithmetic for the browser: one value in
|
|
27
|
+
* the style attribute instead of an expression, and the same result.
|
|
28
|
+
*
|
|
29
|
+
* @param size A rung of the ladder, or a height in px.
|
|
30
|
+
* @param width The artwork's width, in its own units.
|
|
31
|
+
* @param height The artwork's height, in the same units.
|
|
32
|
+
*/
|
|
33
|
+
function brandWidth(size, width, height) {
|
|
34
|
+
return typeof size === "number" ? `${size * width / height / 16}rem` : `calc(${RUNG_HEIGHTS[size]} * ${width} / ${height})`;
|
|
35
|
+
}
|
|
36
|
+
/** Each tone's pair, all six values from the token layer or from the caller. */
|
|
37
|
+
const BRAND_INKS = {
|
|
38
|
+
inherit: {
|
|
39
|
+
fill: "currentColor",
|
|
40
|
+
knockout: "var(--cue-bg)"
|
|
41
|
+
},
|
|
42
|
+
fg: {
|
|
43
|
+
fill: "var(--cue-fg)",
|
|
44
|
+
knockout: "var(--cue-bg)"
|
|
45
|
+
},
|
|
46
|
+
accent: {
|
|
47
|
+
fill: "var(--cue-accent)",
|
|
48
|
+
knockout: "var(--cue-accent-fg)"
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* The paint for a tone.
|
|
53
|
+
*
|
|
54
|
+
* @param tone Which of the three inks to use.
|
|
55
|
+
*/
|
|
56
|
+
function brandInk(tone) {
|
|
57
|
+
return BRAND_INKS[tone];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The attributes that decide whether a mark is a picture or a decoration.
|
|
61
|
+
*
|
|
62
|
+
* A brand asset is usually the second half of something already named — a link
|
|
63
|
+
* that says "CUE++", a header with a heading in it — and a second announcement
|
|
64
|
+
* of the same name is noise. So the default is decorative: `aria-hidden`, and
|
|
65
|
+
* `focusable="false"` because legacy engines put a tabstop on an SVG that has
|
|
66
|
+
* no business having one. Pass a `title` and it becomes a picture instead:
|
|
67
|
+
* `role="img"`, named by the `<title>` the component then renders.
|
|
68
|
+
*
|
|
69
|
+
* @param title The accessible name, when the asset carries one.
|
|
70
|
+
*/
|
|
71
|
+
function brandLabelling(title) {
|
|
72
|
+
return title === void 0 ? {
|
|
73
|
+
"aria-hidden": true,
|
|
74
|
+
focusable: "false"
|
|
75
|
+
} : {
|
|
76
|
+
role: "img",
|
|
77
|
+
focusable: "false"
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
export { brandHeight, brandInk, brandLabelling, brandWidth };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/brand/_geometry.ts
|
|
2
|
+
/** The face, as `plussie.svg` draws it: one circle, centred, full-bleed. */
|
|
3
|
+
const MARK_CIRCLE = {
|
|
4
|
+
cx: 183.5,
|
|
5
|
+
cy: 183.5,
|
|
6
|
+
r: 183.5
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* The two "+" glyphs, in document order.
|
|
10
|
+
*
|
|
11
|
+
* Each is a single path of two crossing rectangles — the vertical bar first,
|
|
12
|
+
* then the horizontal one — which is why an eye can be transformed as a unit.
|
|
13
|
+
*/
|
|
14
|
+
const MARK_EYES = [{
|
|
15
|
+
side: "left",
|
|
16
|
+
d: "M57.9395 236.4V130.947H84.6006V236.4H57.9395ZM18.5436 197.004V170.343H123.997V197.004H18.5436Z",
|
|
17
|
+
centerX: 71.27,
|
|
18
|
+
centerY: 183.67
|
|
19
|
+
}, {
|
|
20
|
+
side: "right",
|
|
21
|
+
d: "M171.535 236.4V130.947H198.196V236.4H171.535ZM132.139 197.004V170.343H237.592V197.004H132.139Z",
|
|
22
|
+
centerX: 184.87,
|
|
23
|
+
centerY: 183.67
|
|
24
|
+
}];
|
|
25
|
+
/**
|
|
26
|
+
* The mark, as the logotype draws it: one `evenodd` path, so the two "+"
|
|
27
|
+
* glyphs are holes rather than ink.
|
|
28
|
+
*
|
|
29
|
+
* Not the same numbers as {@link MARK_CIRCLE} and {@link MARK_EYES}: the
|
|
30
|
+
* lock-up's mark is the standalone one squeezed to 96.777% of its width, and
|
|
31
|
+
* the artwork carries that squeeze in the path rather than in a transform.
|
|
32
|
+
*/
|
|
33
|
+
const LOGOTYPE_MARK_PATH = "M778 183.5C778 284.844 698.492 367 600.413 367C502.335 367 422.826 284.844 422.826 183.5C422.826 82.1558 502.335 0 600.413 0C698.492 0 778 82.1558 778 183.5ZM478.899 236.4V197.004H440.773V170.343H478.899V130.947H504.701V170.343H542.828V197.004H504.701V236.4H478.899ZM588.834 197.004V236.4H614.636V197.004H652.762V170.343H614.636V130.947H588.834V170.343H550.707V197.004H588.834Z";
|
|
34
|
+
/** `C`, `U` and `E`, in reading order, verbatim from `cue++.svg`. */
|
|
35
|
+
const LOGOTYPE_LETTER_PATHS = [
|
|
36
|
+
"M136.396 160.524H103.981C103.389 156.289 102.18 152.529 100.354 149.241C98.5289 145.903 96.1853 143.064 93.3237 140.723C90.4621 138.382 87.1564 136.588 83.4067 135.343C79.7063 134.098 75.6852 133.475 71.3434 133.475C63.4986 133.475 56.6652 135.443 50.8433 139.378C45.0213 143.263 40.5069 148.942 37.2999 156.414C34.0929 163.836 32.4894 172.852 32.4894 183.463C32.4894 194.372 34.0929 203.537 37.2999 210.96C40.5562 218.382 45.0953 223.986 50.9173 227.772C56.7392 231.557 63.4739 233.45 71.1214 233.45C75.4138 233.45 79.3856 232.877 83.0366 231.732C86.737 230.586 90.018 228.917 92.8796 226.726C95.7413 224.484 98.1095 221.769 99.9844 218.581C101.909 215.393 103.241 211.757 103.981 207.672L136.396 207.821C135.557 214.845 133.461 221.62 130.106 228.145C126.8 234.621 122.335 240.424 116.71 245.555C111.135 250.636 104.474 254.671 96.7281 257.66C89.0312 260.599 80.323 262.068 70.6033 262.068C57.0846 262.068 44.9967 258.98 34.3396 252.803C23.7318 246.626 15.3443 237.684 9.17695 225.978C3.05898 214.272 0 200.1 0 183.463C0 166.775 3.10832 152.578 9.32497 140.872C15.5416 129.166 23.9785 120.249 34.6356 114.122C45.2927 107.946 57.2819 104.857 70.6033 104.857C79.3856 104.857 87.5264 106.102 95.0259 108.593C102.575 111.084 109.26 114.72 115.082 119.502C120.904 124.235 125.64 130.038 129.291 136.912C132.992 143.786 135.36 151.657 136.396 160.524Z",
|
|
37
|
+
"M249.036 106.949H281.081V206.327C281.081 217.485 278.441 227.249 273.162 235.617C267.932 243.986 260.605 250.511 251.182 255.194C241.758 259.826 230.78 262.143 218.248 262.143C205.667 262.143 194.665 259.826 185.241 255.194C175.817 250.511 168.491 243.986 163.261 235.617C158.031 227.249 155.416 217.485 155.416 206.327V106.949H187.461V203.562C187.461 209.39 188.719 214.571 191.236 219.104C193.801 223.637 197.403 227.199 202.041 229.789C206.679 232.379 212.081 233.674 218.248 233.674C224.465 233.674 229.868 232.379 234.456 229.789C239.094 227.199 242.671 223.637 245.187 219.104C247.753 214.571 249.036 209.39 249.036 203.562V106.949Z",
|
|
38
|
+
"M303.486 259.976V106.949H405.617V133.624H335.532V170.088H400.362V196.763H335.532V233.301H405.913V259.976H303.486Z"
|
|
39
|
+
];
|
|
40
|
+
//#endregion
|
|
41
|
+
export { LOGOTYPE_LETTER_PATHS, LOGOTYPE_MARK_PATH, MARK_CIRCLE, MARK_EYES };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BrandAssetProps } from "./_chassis.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
//#region src/brand/cue-logotype.d.ts
|
|
4
|
+
interface CueLogotypeProps extends BrandAssetProps {}
|
|
5
|
+
/**
|
|
6
|
+
* The CUE++ logotype: the wordmark and the mark, locked up.
|
|
7
|
+
*
|
|
8
|
+
* 778:367, and it stays that shape at every size — `size` sets the height and
|
|
9
|
+
* the width follows, so a logotype and a {@link CueMark} beside it line up on
|
|
10
|
+
* the same row of a toolbar without either being measured by hand.
|
|
11
|
+
*
|
|
12
|
+
* One paint, not two. The artwork draws the lock-up's mark as a single
|
|
13
|
+
* `evenodd` path, which makes its two "+" glyphs holes rather than ink: they
|
|
14
|
+
* show whatever the logotype is standing on, so the whole thing is one
|
|
15
|
+
* `fill` and there is nothing to keep in step with a background.
|
|
16
|
+
*
|
|
17
|
+
* Decorative by default, like every asset in this group — pass a `title` only
|
|
18
|
+
* when nothing else on the page names the product.
|
|
19
|
+
*
|
|
20
|
+
* Static markup — no `"use client"`.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* <CueLogotype />
|
|
24
|
+
* @example
|
|
25
|
+
* <CueLogotype size="lg" title="CUE++" />
|
|
26
|
+
*/
|
|
27
|
+
declare const CueLogotype: React.ForwardRefExoticComponent<CueLogotypeProps & React.RefAttributes<SVGSVGElement>>;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { CueLogotype, CueLogotypeProps };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { cn } from "../lib/cn.js";
|
|
2
|
+
import { brandHeight, brandInk, brandLabelling, brandWidth } from "./_chassis.js";
|
|
3
|
+
import { LOGOTYPE_LETTER_PATHS, LOGOTYPE_MARK_PATH } from "./_geometry.js";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/brand/cue-logotype.tsx
|
|
7
|
+
/**
|
|
8
|
+
* The CUE++ logotype: the wordmark and the mark, locked up.
|
|
9
|
+
*
|
|
10
|
+
* 778:367, and it stays that shape at every size — `size` sets the height and
|
|
11
|
+
* the width follows, so a logotype and a {@link CueMark} beside it line up on
|
|
12
|
+
* the same row of a toolbar without either being measured by hand.
|
|
13
|
+
*
|
|
14
|
+
* One paint, not two. The artwork draws the lock-up's mark as a single
|
|
15
|
+
* `evenodd` path, which makes its two "+" glyphs holes rather than ink: they
|
|
16
|
+
* show whatever the logotype is standing on, so the whole thing is one
|
|
17
|
+
* `fill` and there is nothing to keep in step with a background.
|
|
18
|
+
*
|
|
19
|
+
* Decorative by default, like every asset in this group — pass a `title` only
|
|
20
|
+
* when nothing else on the page names the product.
|
|
21
|
+
*
|
|
22
|
+
* Static markup — no `"use client"`.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* <CueLogotype />
|
|
26
|
+
* @example
|
|
27
|
+
* <CueLogotype size="lg" title="CUE++" />
|
|
28
|
+
*/
|
|
29
|
+
const CueLogotype = React.forwardRef(function CueLogotype({ className, size = "md", tone = "inherit", title, style, ...elementProps }, ref) {
|
|
30
|
+
const ink = brandInk(tone).fill;
|
|
31
|
+
const height = brandHeight(size);
|
|
32
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
33
|
+
ref,
|
|
34
|
+
viewBox: `0 0 778 367`,
|
|
35
|
+
fill: "none",
|
|
36
|
+
className: cn("inline-block shrink-0 align-middle", className),
|
|
37
|
+
style: {
|
|
38
|
+
height,
|
|
39
|
+
width: brandWidth(size, 778, 367),
|
|
40
|
+
...style
|
|
41
|
+
},
|
|
42
|
+
...brandLabelling(title),
|
|
43
|
+
...elementProps,
|
|
44
|
+
children: [
|
|
45
|
+
title === void 0 ? null : /* @__PURE__ */ jsx("title", { children: title }),
|
|
46
|
+
/* @__PURE__ */ jsx("path", {
|
|
47
|
+
fillRule: "evenodd",
|
|
48
|
+
clipRule: "evenodd",
|
|
49
|
+
d: LOGOTYPE_MARK_PATH,
|
|
50
|
+
fill: ink
|
|
51
|
+
}),
|
|
52
|
+
LOGOTYPE_LETTER_PATHS.map((d, index) => /* @__PURE__ */ jsx("path", {
|
|
53
|
+
d,
|
|
54
|
+
fill: ink
|
|
55
|
+
}, index))
|
|
56
|
+
]
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
//#endregion
|
|
60
|
+
export { CueLogotype };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { BrandAssetProps } from "./_chassis.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
//#region src/brand/cue-mark.d.ts
|
|
4
|
+
interface CueMarkProps extends BrandAssetProps {}
|
|
5
|
+
/**
|
|
6
|
+
* The CUE++ mark: the circular one, with no words in it.
|
|
7
|
+
*
|
|
8
|
+
* Square at every size, drawn from the artwork's own path data, and painted
|
|
9
|
+
* entirely from tokens — the disc takes the tone's ink and the two "+" glyphs
|
|
10
|
+
* take the ground, which is exactly the relationship the two shipped SVGs
|
|
11
|
+
* encode by hand. One element is therefore correct in all eight presets and
|
|
12
|
+
* both modes, and there is no light/dark variant to pick.
|
|
13
|
+
*
|
|
14
|
+
* The two glyphs are {@link Plussie}'s eyes; both components read one geometry
|
|
15
|
+
* module, so the mark cannot stop being the character's face.
|
|
16
|
+
*
|
|
17
|
+
* Decorative by default. It renders `aria-hidden` unless you give it a `title`,
|
|
18
|
+
* because a mark beside a wordmark, a heading or a link that already says
|
|
19
|
+
* "CUE++" is the second time a reader is told.
|
|
20
|
+
*
|
|
21
|
+
* Static markup — no `"use client"`.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* <CueMark />
|
|
25
|
+
* @example
|
|
26
|
+
* <CueMark size="lg" tone="accent" title="CUE++" />
|
|
27
|
+
*/
|
|
28
|
+
declare const CueMark: React.ForwardRefExoticComponent<CueMarkProps & React.RefAttributes<SVGSVGElement>>;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { CueMark, CueMarkProps };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { cn } from "../lib/cn.js";
|
|
2
|
+
import { brandHeight, brandInk, brandLabelling } from "./_chassis.js";
|
|
3
|
+
import { MARK_CIRCLE, MARK_EYES } from "./_geometry.js";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/brand/cue-mark.tsx
|
|
7
|
+
/**
|
|
8
|
+
* The CUE++ mark: the circular one, with no words in it.
|
|
9
|
+
*
|
|
10
|
+
* Square at every size, drawn from the artwork's own path data, and painted
|
|
11
|
+
* entirely from tokens — the disc takes the tone's ink and the two "+" glyphs
|
|
12
|
+
* take the ground, which is exactly the relationship the two shipped SVGs
|
|
13
|
+
* encode by hand. One element is therefore correct in all eight presets and
|
|
14
|
+
* both modes, and there is no light/dark variant to pick.
|
|
15
|
+
*
|
|
16
|
+
* The two glyphs are {@link Plussie}'s eyes; both components read one geometry
|
|
17
|
+
* module, so the mark cannot stop being the character's face.
|
|
18
|
+
*
|
|
19
|
+
* Decorative by default. It renders `aria-hidden` unless you give it a `title`,
|
|
20
|
+
* because a mark beside a wordmark, a heading or a link that already says
|
|
21
|
+
* "CUE++" is the second time a reader is told.
|
|
22
|
+
*
|
|
23
|
+
* Static markup — no `"use client"`.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* <CueMark />
|
|
27
|
+
* @example
|
|
28
|
+
* <CueMark size="lg" tone="accent" title="CUE++" />
|
|
29
|
+
*/
|
|
30
|
+
const CueMark = React.forwardRef(function CueMark({ className, size = "md", tone = "inherit", title, style, ...elementProps }, ref) {
|
|
31
|
+
const ink = brandInk(tone);
|
|
32
|
+
const height = brandHeight(size);
|
|
33
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
34
|
+
ref,
|
|
35
|
+
viewBox: `0 0 367 367`,
|
|
36
|
+
fill: "none",
|
|
37
|
+
className: cn("inline-block shrink-0 align-middle", className),
|
|
38
|
+
style: {
|
|
39
|
+
width: height,
|
|
40
|
+
height,
|
|
41
|
+
...style
|
|
42
|
+
},
|
|
43
|
+
...brandLabelling(title),
|
|
44
|
+
...elementProps,
|
|
45
|
+
children: [
|
|
46
|
+
title === void 0 ? null : /* @__PURE__ */ jsx("title", { children: title }),
|
|
47
|
+
/* @__PURE__ */ jsx("circle", {
|
|
48
|
+
cx: MARK_CIRCLE.cx,
|
|
49
|
+
cy: MARK_CIRCLE.cy,
|
|
50
|
+
r: MARK_CIRCLE.r,
|
|
51
|
+
fill: ink.fill
|
|
52
|
+
}),
|
|
53
|
+
MARK_EYES.map((eye) => /* @__PURE__ */ jsx("path", {
|
|
54
|
+
d: eye.d,
|
|
55
|
+
fill: ink.knockout
|
|
56
|
+
}, eye.side))
|
|
57
|
+
]
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
//#endregion
|
|
61
|
+
export { CueMark };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { BrandAssetProps, BrandSize, BrandTone } from "./_chassis.js";
|
|
2
|
+
import { CueLogotype, CueLogotypeProps } from "./cue-logotype.js";
|
|
3
|
+
import { CueMark, CueMarkProps } from "./cue-mark.js";
|
|
4
|
+
import { Plussie, PlussieExpression, PlussieProps } from "./plussie.js";
|
|
5
|
+
export { type BrandAssetProps, type BrandSize, type BrandTone, CueLogotype, type CueLogotypeProps, CueMark, type CueMarkProps, Plussie, type PlussieExpression, type PlussieProps };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { BrandAssetProps } from "./_chassis.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
//#region src/brand/plussie.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The poses Plussie can hold.
|
|
6
|
+
*
|
|
7
|
+
* Every one of them is a still taken out of the animation rig in
|
|
8
|
+
* `site/src/remotion/plussie/animations/`, at the frame where the pose is
|
|
9
|
+
* fullest — nothing here is invented, and nothing here needs Remotion:
|
|
10
|
+
*
|
|
11
|
+
* | Expression | Source | Frame |
|
|
12
|
+
* | --- | --- | --- |
|
|
13
|
+
* | `blink` | `01-Blink.tsx` | the midpoint of `blinkScaleY`, where both eyes are `scaleY(0.05)` |
|
|
14
|
+
* | `wink` | `02-Wink.tsx` | the same midpoint, left eye only |
|
|
15
|
+
* | `look-left` / `look-right` | `03-LookAround.tsx` | the held stops of its keyframe track, ±15 |
|
|
16
|
+
* | `look-up` / `look-down` | `04-LookUpDown.tsx` | the held stops of its track, ±12 |
|
|
17
|
+
*/
|
|
18
|
+
type PlussieExpression = "default" | "blink" | "wink" | "look-left" | "look-right" | "look-up" | "look-down";
|
|
19
|
+
interface PlussieProps extends BrandAssetProps {
|
|
20
|
+
/**
|
|
21
|
+
* Which pose to hold. Defaults to `"default"`, eyes open and level.
|
|
22
|
+
*
|
|
23
|
+
* Every pose is a still from the character's own animations rather than a
|
|
24
|
+
* new drawing, so a screen that holds one and a video that plays through it
|
|
25
|
+
* agree.
|
|
26
|
+
*/
|
|
27
|
+
expression?: PlussieExpression;
|
|
28
|
+
/**
|
|
29
|
+
* Blink every few seconds, on a CSS keyframe. Defaults to `false`.
|
|
30
|
+
*
|
|
31
|
+
* Off by default because a mark that moves in the corner of the eye is a
|
|
32
|
+
* distraction on a console screen, and off again for a reader who has asked
|
|
33
|
+
* for reduced motion — the rule that drives it is inside a
|
|
34
|
+
* `prefers-reduced-motion` guard, so there is no state to keep and nothing to
|
|
35
|
+
* turn off a second time.
|
|
36
|
+
*
|
|
37
|
+
* It composes with `expression`: a winking Plussie blinks its open eye.
|
|
38
|
+
*/
|
|
39
|
+
idle?: boolean;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Plussie, the CUE++ character — the mark, with its eyes free to move.
|
|
43
|
+
*
|
|
44
|
+
* The same circle and the same two "+" glyphs {@link CueMark} draws, out of the
|
|
45
|
+
* same geometry module, because they are the same drawing: the mark's glyphs
|
|
46
|
+
* *are* the character's eyes. What this adds is that the eyes are their own
|
|
47
|
+
* groups, so an `expression` can slide or shut them.
|
|
48
|
+
*
|
|
49
|
+
* Static-first. The eight Remotion animations this character was rigged for
|
|
50
|
+
* stay in the site that renders video; a heavy, video-oriented peer has no
|
|
51
|
+
* business in a component library, so what is ported here is the geometry and
|
|
52
|
+
* the poses. Everything else a caller wants — a look that follows the cursor, a
|
|
53
|
+
* blink on a timer of their own — is a `expression` prop away, driven by their
|
|
54
|
+
* own runtime.
|
|
55
|
+
*
|
|
56
|
+
* Static markup — no `"use client"`.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* <Plussie size="lg" title="Plussie" />
|
|
60
|
+
* @example
|
|
61
|
+
* <Plussie expression="wink" tone="accent" />
|
|
62
|
+
* @example
|
|
63
|
+
* <Plussie size={96} idle />
|
|
64
|
+
*/
|
|
65
|
+
declare const Plussie: React.ForwardRefExoticComponent<PlussieProps & React.RefAttributes<SVGSVGElement>>;
|
|
66
|
+
//#endregion
|
|
67
|
+
export { Plussie, PlussieExpression, PlussieProps };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { cn } from "../lib/cn.js";
|
|
2
|
+
import { brandHeight, brandInk, brandLabelling } from "./_chassis.js";
|
|
3
|
+
import { MARK_CIRCLE, MARK_EYES } from "./_geometry.js";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/brand/plussie.tsx
|
|
7
|
+
/** `blinkScaleY`'s value at the midpoint of a blink: shut, but still a line. */
|
|
8
|
+
const EYE_CLOSED = .05;
|
|
9
|
+
/** `03-LookAround.tsx`'s held stop. */
|
|
10
|
+
const LOOK_X = 15;
|
|
11
|
+
/** `04-LookUpDown.tsx`'s held stop. */
|
|
12
|
+
const LOOK_Y = 12;
|
|
13
|
+
/** Each expression as a pair of eye poses. `default` moves nothing. */
|
|
14
|
+
const EXPRESSIONS = {
|
|
15
|
+
default: {
|
|
16
|
+
left: {},
|
|
17
|
+
right: {}
|
|
18
|
+
},
|
|
19
|
+
blink: {
|
|
20
|
+
left: { sy: EYE_CLOSED },
|
|
21
|
+
right: { sy: EYE_CLOSED }
|
|
22
|
+
},
|
|
23
|
+
wink: {
|
|
24
|
+
left: { sy: EYE_CLOSED },
|
|
25
|
+
right: {}
|
|
26
|
+
},
|
|
27
|
+
"look-left": {
|
|
28
|
+
left: { dx: -15 },
|
|
29
|
+
right: { dx: -15 }
|
|
30
|
+
},
|
|
31
|
+
"look-right": {
|
|
32
|
+
left: { dx: LOOK_X },
|
|
33
|
+
right: { dx: LOOK_X }
|
|
34
|
+
},
|
|
35
|
+
"look-up": {
|
|
36
|
+
left: { dy: -12 },
|
|
37
|
+
right: { dy: -12 }
|
|
38
|
+
},
|
|
39
|
+
"look-down": {
|
|
40
|
+
left: { dy: LOOK_Y },
|
|
41
|
+
right: { dy: LOOK_Y }
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* A pose as an SVG `transform`, or `undefined` when there is nothing to apply.
|
|
46
|
+
*
|
|
47
|
+
* The attribute rather than the CSS property, deliberately: the idle blink is a
|
|
48
|
+
* CSS animation on the group inside this one, and a CSS `transform` there would
|
|
49
|
+
* override a CSS `transform` here. Two mechanisms on two elements is what lets
|
|
50
|
+
* a winking Plussie also blink.
|
|
51
|
+
*
|
|
52
|
+
* @param pose Where the eye should sit.
|
|
53
|
+
* @param eye The eye, for the centre a squash happens about.
|
|
54
|
+
*/
|
|
55
|
+
function eyeTransform(pose, eye) {
|
|
56
|
+
const parts = [];
|
|
57
|
+
if (pose.dx !== void 0 || pose.dy !== void 0) parts.push(`translate(${pose.dx ?? 0} ${pose.dy ?? 0})`);
|
|
58
|
+
if (pose.sy !== void 0) parts.push(`translate(${eye.centerX} ${eye.centerY}) scale(1 ${pose.sy}) translate(${-eye.centerX} ${-eye.centerY})`);
|
|
59
|
+
return parts.length === 0 ? void 0 : parts.join(" ");
|
|
60
|
+
}
|
|
61
|
+
/** The class `styles.css` attaches the idle blink's keyframes to. */
|
|
62
|
+
const IDLE_CLASS = "cue-plussie-idle";
|
|
63
|
+
/**
|
|
64
|
+
* Plussie, the CUE++ character — the mark, with its eyes free to move.
|
|
65
|
+
*
|
|
66
|
+
* The same circle and the same two "+" glyphs {@link CueMark} draws, out of the
|
|
67
|
+
* same geometry module, because they are the same drawing: the mark's glyphs
|
|
68
|
+
* *are* the character's eyes. What this adds is that the eyes are their own
|
|
69
|
+
* groups, so an `expression` can slide or shut them.
|
|
70
|
+
*
|
|
71
|
+
* Static-first. The eight Remotion animations this character was rigged for
|
|
72
|
+
* stay in the site that renders video; a heavy, video-oriented peer has no
|
|
73
|
+
* business in a component library, so what is ported here is the geometry and
|
|
74
|
+
* the poses. Everything else a caller wants — a look that follows the cursor, a
|
|
75
|
+
* blink on a timer of their own — is a `expression` prop away, driven by their
|
|
76
|
+
* own runtime.
|
|
77
|
+
*
|
|
78
|
+
* Static markup — no `"use client"`.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* <Plussie size="lg" title="Plussie" />
|
|
82
|
+
* @example
|
|
83
|
+
* <Plussie expression="wink" tone="accent" />
|
|
84
|
+
* @example
|
|
85
|
+
* <Plussie size={96} idle />
|
|
86
|
+
*/
|
|
87
|
+
const Plussie = React.forwardRef(function Plussie({ className, size = "md", tone = "inherit", title, expression = "default", idle = false, style, ...elementProps }, ref) {
|
|
88
|
+
const ink = brandInk(tone);
|
|
89
|
+
const height = brandHeight(size);
|
|
90
|
+
const pose = EXPRESSIONS[expression];
|
|
91
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
92
|
+
ref,
|
|
93
|
+
viewBox: `0 0 367 367`,
|
|
94
|
+
fill: "none",
|
|
95
|
+
className: cn("inline-block shrink-0 align-middle", className),
|
|
96
|
+
style: {
|
|
97
|
+
width: height,
|
|
98
|
+
height,
|
|
99
|
+
...style
|
|
100
|
+
},
|
|
101
|
+
...brandLabelling(title),
|
|
102
|
+
...elementProps,
|
|
103
|
+
children: [
|
|
104
|
+
title === void 0 ? null : /* @__PURE__ */ jsx("title", { children: title }),
|
|
105
|
+
/* @__PURE__ */ jsx("circle", {
|
|
106
|
+
cx: MARK_CIRCLE.cx,
|
|
107
|
+
cy: MARK_CIRCLE.cy,
|
|
108
|
+
r: MARK_CIRCLE.r,
|
|
109
|
+
fill: ink.fill
|
|
110
|
+
}),
|
|
111
|
+
MARK_EYES.map((eye) => /* @__PURE__ */ jsx("g", {
|
|
112
|
+
transform: eyeTransform(pose[eye.side], eye),
|
|
113
|
+
children: /* @__PURE__ */ jsx("g", {
|
|
114
|
+
className: idle ? IDLE_CLASS : void 0,
|
|
115
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
116
|
+
d: eye.d,
|
|
117
|
+
fill: ink.knockout
|
|
118
|
+
})
|
|
119
|
+
})
|
|
120
|
+
}, eye.side))
|
|
121
|
+
]
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
//#endregion
|
|
125
|
+
export { Plussie };
|
package/dist/chat/agent-pile.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { agentColor } from "./agent-color.js";
|
|
3
2
|
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { agentColor } from "./agent-color.js";
|
|
4
4
|
import { CrownGlyph } from "./_glyphs.js";
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
package/dist/chat/ask-box.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { AGENT_ROOT_COLOR, agentColor } from "./agent-color.js";
|
|
3
2
|
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { AGENT_ROOT_COLOR, agentColor } from "./agent-color.js";
|
|
4
4
|
import { CheckGlyph } from "./_glyphs.js";
|
|
5
5
|
import { Checkbox } from "../forms/checkbox.js";
|
|
6
6
|
import { Input } from "../forms/input.js";
|
|
@@ -121,7 +121,7 @@ const AskBox = React.forwardRef(function AskBox({ className, question, kind = "t
|
|
|
121
121
|
type: "button",
|
|
122
122
|
"data-slot": "ask-box-summary",
|
|
123
123
|
"aria-expanded": open,
|
|
124
|
-
className: "flex min-w-0 cursor-pointer items-center gap-(--cue-space-2) border-0 bg-transparent p-0 text-start font-mono text-(length:--cue-text-ui) outline-none focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-accent",
|
|
124
|
+
className: "relative flex min-w-0 cursor-pointer items-center gap-(--cue-space-2) border-0 bg-transparent p-0 text-start font-mono text-(length:--cue-text-ui) outline-none focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-accent",
|
|
125
125
|
onClick: () => setOpen((current) => !current),
|
|
126
126
|
children: [
|
|
127
127
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { agentColor } from "./agent-color.js";
|
|
3
2
|
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { agentColor } from "./agent-color.js";
|
|
4
4
|
import { CheckGlyph } from "./_glyphs.js";
|
|
5
5
|
import { Spinner } from "../primitives/spinner.js";
|
|
6
6
|
import * as React from "react";
|
package/dist/chat/message.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AGENT_ROOT_COLOR, agentColor } from "./agent-color.js";
|
|
2
1
|
import { cn } from "../lib/cn.js";
|
|
2
|
+
import { AGENT_ROOT_COLOR, agentColor } from "./agent-color.js";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
//#region src/chat/message.tsx
|
|
@@ -85,7 +85,7 @@ const Message = React.forwardRef(function Message({ className, role = "agent", a
|
|
|
85
85
|
}) : null,
|
|
86
86
|
/* @__PURE__ */ jsxs("div", {
|
|
87
87
|
"data-slot": "message-body",
|
|
88
|
-
className: "min-w-0 text-(length:--cue-text-body) leading-relaxed break-words whitespace-pre-wrap",
|
|
88
|
+
className: "relative min-w-0 text-(length:--cue-text-body) leading-relaxed break-words whitespace-pre-wrap",
|
|
89
89
|
children: [children, pending ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
90
90
|
"data-slot": "message-caret",
|
|
91
91
|
"aria-hidden": "true",
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import "react";
|
|
2
|
+
//#region src/chrome/_edge-scroller.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* The library's one answer to "this strip is wider than the space it has".
|
|
5
|
+
*
|
|
6
|
+
* A bar full of controls has three possible behaviours when it runs out of
|
|
7
|
+
* room: wrap, scroll, or move the surplus into a menu. This system picks
|
|
8
|
+
* **scroll**, once, and every bar that can overflow uses this module.
|
|
9
|
+
*
|
|
10
|
+
* - **Wrapping is out** because every bar here is one rung of the chrome
|
|
11
|
+
* ladder tall (`--cue-chrome-toolbar`) and sits in a layout that has already
|
|
12
|
+
* subtracted that height — `AppShell` gives the toolbar `shrink-0` beside a
|
|
13
|
+
* `min-h-0` scroller. A bar that silently becomes two rows tall steals the
|
|
14
|
+
* work area's height, and the same argument applies to a `SegmentedControl`
|
|
15
|
+
* in a page header's actions slot.
|
|
16
|
+
* - **A "more" menu is out** because it cannot be built from the children a
|
|
17
|
+
* bar actually takes. `Toolbar` accepts arbitrary nodes — buttons, groups,
|
|
18
|
+
* separators, a `Select` — and there is no honest conversion from one of
|
|
19
|
+
* those into a menu item; it would need a parallel `items` data model, a
|
|
20
|
+
* per-item measuring pass on every resize, and it would lift the surplus
|
|
21
|
+
* controls out of Base UI's roving-focus group, so the same button would be
|
|
22
|
+
* reachable by arrow key at one width and by a popover at another.
|
|
23
|
+
* - **Scrolling is what the library already does** — `ScrollableTabsList` has
|
|
24
|
+
* shipped this affordance since the tab strip was written, and its geometry
|
|
25
|
+
* was factored out into `./_tabs-scroll` for exactly this reuse. Nothing is
|
|
26
|
+
* hidden, nothing is re-parented, the roving-focus group stays intact, and
|
|
27
|
+
* the arrow keys still walk the whole bar because a focused control is
|
|
28
|
+
* scrolled into view by the browser.
|
|
29
|
+
*
|
|
30
|
+
* The affordance is two things and needs both: {@link useEdgeScroll} produces
|
|
31
|
+
* the fade mask that softens the cut, and {@link EdgeChevrons} draws the
|
|
32
|
+
* buttons that are the visible half — what sits at an overflowing edge is
|
|
33
|
+
* usually the gap *between* two controls, and fading empty space produces
|
|
34
|
+
* nothing anyone can see.
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* What a bar does when its contents are wider than the space it has.
|
|
38
|
+
*
|
|
39
|
+
* One vocabulary, shared by every bar that can overflow, because there is one
|
|
40
|
+
* behaviour: `"scroll"` is the affordance this module implements, `"clip"` is
|
|
41
|
+
* the escape hatch for a bar already inside something that scrolls.
|
|
42
|
+
*/
|
|
43
|
+
type BarOverflow = "scroll" | "clip";
|
|
44
|
+
//#endregion
|
|
45
|
+
export { BarOverflow };
|