@crisp-ui-kit/crisp 0.33.4 → 0.34.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/checkbox.css +1 -1
- package/dist/checkbox.layered.css +1 -1
- package/dist/cjs/components/avatargroup/avatargroup.recipe.js +21 -8
- package/dist/cjs/components/barchart/barchart.js +6 -1
- package/dist/cjs/components/checkbox/checkbox.recipe.js +50 -17
- package/dist/cjs/components/datepicker/datepicker.js +7 -1
- package/dist/cjs/components/kbd/kbd.recipe.js +22 -9
- package/dist/cjs/components/linechart/linechart.js +6 -1
- package/dist/cjs/components/skeleton/skeleton.recipe.js +14 -8
- package/dist/cjs/components/table/table.js +6 -2
- package/dist/cjs/components/textarea/textarea.js +9 -2
- package/dist/cjs/components/textarea/textarea.recipe.js +14 -5
- package/dist/cjs/components/tooltip/tooltip.recipe.js +27 -6
- package/dist/cjs/product/recordpage/recordpage.js +1 -1
- package/dist/command.css +1 -1
- package/dist/command.layered.css +1 -1
- package/dist/esm/components/avatargroup/avatargroup.recipe.js +21 -8
- package/dist/esm/components/barchart/barchart.js +6 -1
- package/dist/esm/components/checkbox/checkbox.recipe.js +50 -17
- package/dist/esm/components/datepicker/datepicker.js +7 -1
- package/dist/esm/components/kbd/kbd.recipe.js +22 -9
- package/dist/esm/components/linechart/linechart.js +6 -1
- package/dist/esm/components/skeleton/skeleton.recipe.js +14 -8
- package/dist/esm/components/table/table.js +6 -2
- package/dist/esm/components/textarea/textarea.js +9 -2
- package/dist/esm/components/textarea/textarea.recipe.js +14 -5
- package/dist/esm/components/tooltip/tooltip.recipe.js +27 -6
- package/dist/esm/product/recordpage/recordpage.js +1 -1
- package/dist/navitem.css +1 -1
- package/dist/navitem.layered.css +1 -1
- package/dist/sidebar.css +1 -1
- package/dist/sidebar.layered.css +1 -1
- package/dist/styles.css +6 -90
- package/dist/styles.layered.css +6 -90
- package/dist/textarea.css +2 -2
- package/dist/textarea.layered.css +2 -2
- package/dist/tokens.css +0 -84
- package/dist/types/components/avatargroup/avatargroup.recipe.d.ts +25 -2
- package/dist/types/components/checkbox/checkbox.recipe.d.ts +51 -3
- package/dist/types/components/kbd/kbd.recipe.d.ts +24 -3
- package/dist/types/components/skeleton/skeleton.recipe.d.ts +19 -2
- package/dist/types/components/tooltip/tooltip.recipe.d.ts +30 -2
- package/package.json +2 -1
package/dist/checkbox.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
.crisp-checkbox {
|
|
2
|
-
appearance: none; -webkit-appearance: none; box-sizing: border-box; flex-shrink: 0; margin: 0; width: 16px; height: 16px; border: none; border-radius: var(--crisp-radius-sm)
|
|
2
|
+
appearance: none; -webkit-appearance: none; box-sizing: border-box; flex-shrink: 0; margin: 0; width: 16px; height: 16px; border: none; border-radius: var(--crisp-radius-sm); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 9%, transparent); cursor: pointer; transition: background-color .12s, box-shadow .12s;
|
|
3
3
|
&:hover { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 30%, transparent); }
|
|
4
4
|
&:checked, &:indeterminate { background: var(--crisp-bg-brand-solid) center / 10px no-repeat; box-shadow: none; }
|
|
5
5
|
&:checked { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 6.5 5 9l4.5-5'/%3E%3C/svg%3E"); }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
@layer crisp-components {
|
|
2
2
|
.crisp-checkbox {
|
|
3
|
-
appearance: none; -webkit-appearance: none; box-sizing: border-box; flex-shrink: 0; margin: 0; width: 16px; height: 16px; border: none; border-radius: var(--crisp-radius-sm)
|
|
3
|
+
appearance: none; -webkit-appearance: none; box-sizing: border-box; flex-shrink: 0; margin: 0; width: 16px; height: 16px; border: none; border-radius: var(--crisp-radius-sm); background: var(--crisp-bg-surface); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 9%, transparent); cursor: pointer; transition: background-color .12s, box-shadow .12s;
|
|
4
4
|
&:hover { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-fg-primary) 30%, transparent); }
|
|
5
5
|
&:checked, &:indeterminate { background: var(--crisp-bg-brand-solid) center / 10px no-repeat; box-shadow: none; }
|
|
6
6
|
&:checked { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 6.5 5 9l4.5-5'/%3E%3C/svg%3E"); }
|
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.avatargroupRecipe = void 0;
|
|
3
|
+
exports.spec = exports.avatargroupRecipe = void 0;
|
|
4
4
|
const core_1 = require("../../core");
|
|
5
5
|
const tokens_1 = require("../../tokens");
|
|
6
6
|
// A row of overlapping avatars — each ringed in the surface colour so it reads
|
|
7
7
|
// against its neighbour, with a "+N" overflow chip.
|
|
8
|
-
const
|
|
8
|
+
const spec = (0, core_1.defineSpec)({
|
|
9
9
|
name: "avatargroup",
|
|
10
|
-
base:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
base: { display: "inline-flex", alignItems: "center" },
|
|
11
|
+
parts: [
|
|
12
|
+
{
|
|
13
|
+
slot: "member",
|
|
14
|
+
selector: "& > *",
|
|
15
|
+
decls: {
|
|
16
|
+
marginInlineStart: `-${tokens_1.contract.space["2"]}`,
|
|
17
|
+
boxShadow: `0 0 0 2px ${tokens_1.contract.bgSurface}`,
|
|
18
|
+
position: "relative",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
slot: "member",
|
|
23
|
+
selector: "& > *:first-child",
|
|
24
|
+
decls: { marginInlineStart: 0 },
|
|
25
|
+
},
|
|
26
|
+
],
|
|
16
27
|
});
|
|
28
|
+
exports.spec = spec;
|
|
29
|
+
const config = (0, core_1.specToRecipe)(spec);
|
|
17
30
|
exports.avatargroupRecipe = (0, core_1.resolveRecipe)(config);
|
|
18
31
|
exports.default = config;
|
|
@@ -34,9 +34,14 @@ function BarChart({ data, height = 240, max, ticks = 5, color, format = (n) => n
|
|
|
34
34
|
: `max(34px, ${longestTickChars}ch + ${tokens_1.contract.space["4"]})`;
|
|
35
35
|
const summary = ariaLabel ??
|
|
36
36
|
`Bar chart: ${data.map((d) => `${d.label} ${format(d.value)}`).join(", ")}`;
|
|
37
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, barchart_recipe_1.barchartRecipe)({ className }), ...rest,
|
|
37
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, barchart_recipe_1.barchartRecipe)({ className }), ...rest,
|
|
38
|
+
// merged, not assigned: written plainly this sits AFTER `{...rest}` and
|
|
39
|
+
// overwrites whatever style the consumer passed, so `style={{ maxWidth }}`
|
|
40
|
+
// on the chart did nothing at all. The consumer's wins on collision.
|
|
41
|
+
style: {
|
|
38
42
|
height,
|
|
39
43
|
"--crisp-barchart-yaxis-width": yAxisWidthValue,
|
|
44
|
+
...rest.style,
|
|
40
45
|
}, role: "img", "aria-label": summary, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-barchart-body", children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-barchart-yaxis", children: tickValues.map((t) => ((0, jsx_runtime_1.jsx)("span", { className: "crisp-barchart-ytick", style: { bottom: `${(t / top) * 100}%` }, children: format(t) }, t))) }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-barchart-plot", children: [tickValues.map((t) => ((0, jsx_runtime_1.jsx)("div", { className: "crisp-barchart-grid", style: { bottom: `${(t / top) * 100}%` } }, t))), data.map((d) => ((0, jsx_runtime_1.jsx)("div", { className: "crisp-barchart-col", children: (0, jsx_runtime_1.jsx)("div", { className: "crisp-barchart-bar", "data-empty": d.value <= 0 ? "" : undefined, style: {
|
|
41
46
|
height: `${Math.max(0, (d.value / top) * 100)}%`,
|
|
42
47
|
background: color,
|
|
@@ -1,28 +1,61 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.checkboxRecipe = void 0;
|
|
3
|
+
exports.spec = exports.checkboxRecipe = void 0;
|
|
4
4
|
const core_1 = require("../../core");
|
|
5
5
|
const tokens_1 = require("../../tokens");
|
|
6
6
|
// A 16px square checkbox measured from a record grid: r6, a subtle 1px
|
|
7
7
|
// inset ring when empty, brand fill + white check when on. The check is a
|
|
8
8
|
// data-URI SVG background so it renders reliably (input pseudo-content doesn't).
|
|
9
9
|
const CHECK = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 6.5 5 9l4.5-5'/%3E%3C/svg%3E\")";
|
|
10
|
-
const
|
|
10
|
+
const spec = (0, core_1.defineSpec)({
|
|
11
11
|
name: "checkbox",
|
|
12
|
-
base:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
12
|
+
base: {
|
|
13
|
+
appearance: "none",
|
|
14
|
+
WebkitAppearance: "none",
|
|
15
|
+
boxSizing: "border-box",
|
|
16
|
+
flexShrink: 0,
|
|
17
|
+
margin: 0,
|
|
18
|
+
width: "16px",
|
|
19
|
+
height: "16px",
|
|
20
|
+
border: "none",
|
|
21
|
+
borderRadius: tokens_1.contract.radius.sm,
|
|
22
|
+
background: tokens_1.contract.bgSurface,
|
|
23
|
+
boxShadow: `inset 0 0 0 1px color-mix(in srgb, ${tokens_1.contract.fgPrimary} 9%, transparent)`,
|
|
24
|
+
cursor: "pointer",
|
|
25
|
+
transition: "background-color .12s, box-shadow .12s",
|
|
26
|
+
},
|
|
27
|
+
parts: [
|
|
28
|
+
{
|
|
29
|
+
selector: "&:hover",
|
|
30
|
+
decls: {
|
|
31
|
+
boxShadow: `inset 0 0 0 1px color-mix(in srgb, ${tokens_1.contract.fgPrimary} 30%, transparent)`,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
selector: "&:checked, &:indeterminate",
|
|
36
|
+
decls: {
|
|
37
|
+
background: `${tokens_1.contract.bgBrandSolid} center / 10px no-repeat`,
|
|
38
|
+
boxShadow: "none",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{ selector: "&:checked", decls: { backgroundImage: CHECK } },
|
|
42
|
+
{
|
|
43
|
+
selector: "&:indeterminate",
|
|
44
|
+
decls: {
|
|
45
|
+
backgroundImage: `linear-gradient(${tokens_1.contract.fgOnBrand}, ${tokens_1.contract.fgOnBrand})`,
|
|
46
|
+
backgroundSize: "8px 2px",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
selector: "&:focus-visible",
|
|
51
|
+
decls: {
|
|
52
|
+
outline: `2px solid ${tokens_1.contract.bgBrandSolid}`,
|
|
53
|
+
outlineOffset: "1px",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
],
|
|
27
57
|
});
|
|
58
|
+
exports.spec = spec;
|
|
59
|
+
const config = (0, core_1.specToRecipe)(spec);
|
|
60
|
+
exports.checkboxRecipe = Object.assign((0, core_1.resolveRecipe)(config), { config });
|
|
28
61
|
exports.default = config;
|
|
@@ -126,7 +126,13 @@ const DatePickerImplementation = React.forwardRef((props, forwardedRef) => {
|
|
|
126
126
|
}, ...(0, dom_utils_1.mergeProps)(api.rootProps, rootProps), "aria-label": rootAriaLabel, "aria-labelledby": ariaLabelledby, className: (0, datepicker_recipe_1.datepickerRecipe)({
|
|
127
127
|
visibleRange: api.visibleRange,
|
|
128
128
|
className,
|
|
129
|
-
}),
|
|
129
|
+
}),
|
|
130
|
+
// merged: this sits after the spread above, so assigning it plainly
|
|
131
|
+
// dropped any style the consumer passed. Theirs wins on collision.
|
|
132
|
+
style: {
|
|
133
|
+
...styleOf({ height, minHeight, maxHeight }),
|
|
134
|
+
...rootProps?.style,
|
|
135
|
+
}, children: [api.visibleRange === "continuous" ? ((0, jsx_runtime_1.jsxs)("div", { ref: api.refs.continuousScroll, ...api.continuousScrollProps, "data-date-picker-continuous-scroll": "", className: "crisp-datepicker-continuous-scroll", children: [(0, jsx_runtime_1.jsx)(WeekdayRow, { api: api, semantic: false }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-datepicker-continuous-content", children: [(0, jsx_runtime_1.jsx)("div", { "aria-hidden": "true", className: "datepicker-continuous-spacer", style: { height: api.virtual.topHeight } }), api.months.map((month) => ((0, jsx_runtime_1.jsx)(MonthView, { api: api, month: month, renderDateCellContent: renderDateCellContent, renderDateCellSupplement: renderDateCellSupplement, showWeekdays: false, showMonthLabel: true, monthRef: api.refs.continuousMonth(month.key) }, month.key))), (0, jsx_runtime_1.jsx)("div", { "aria-hidden": "true", className: "datepicker-continuous-spacer", style: { height: api.virtual.bottomHeight } })] })] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [api.visibleRange !== "twoMonths" && (0, jsx_runtime_1.jsx)(Header, { api: api }), (0, jsx_runtime_1.jsx)("div", { "data-wheel-open": api.isWheelOpen && api.visibleRange !== "twoMonths"
|
|
130
136
|
? ""
|
|
131
137
|
: undefined, "aria-hidden": api.isWheelOpen && api.visibleRange !== "twoMonths"
|
|
132
138
|
? true
|
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.kbdRecipe = void 0;
|
|
3
|
+
exports.spec = exports.kbdRecipe = void 0;
|
|
4
4
|
const core_1 = require("../../core");
|
|
5
5
|
const tokens_1 = require("../../tokens");
|
|
6
|
-
const
|
|
6
|
+
const spec = (0, core_1.defineSpec)({
|
|
7
7
|
name: "kbd",
|
|
8
|
-
base:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
base: {
|
|
9
|
+
boxSizing: "border-box",
|
|
10
|
+
display: "inline-flex",
|
|
11
|
+
alignItems: "center",
|
|
12
|
+
justifyContent: "center",
|
|
13
|
+
gap: tokens_1.contract.space["0.5"],
|
|
14
|
+
minWidth: "20px",
|
|
15
|
+
height: "20px",
|
|
16
|
+
paddingInline: tokens_1.contract.space["1"],
|
|
17
|
+
borderRadius: tokens_1.contract.radius.sm,
|
|
18
|
+
fontFamily: tokens_1.contract.font.sans,
|
|
19
|
+
fontSize: tokens_1.contract.text.xs,
|
|
20
|
+
fontWeight: tokens_1.contract.weight.regular,
|
|
21
|
+
color: `color-mix(in srgb, ${tokens_1.contract.fgPrimary} 50%, transparent)`,
|
|
22
|
+
background: "transparent",
|
|
23
|
+
boxShadow: `inset 0 0 0 1px color-mix(in srgb, ${tokens_1.contract.fgPrimary} 6%, transparent)`,
|
|
24
|
+
},
|
|
15
25
|
});
|
|
26
|
+
exports.spec = spec;
|
|
27
|
+
const config = (0, core_1.specToRecipe)(spec);
|
|
28
|
+
exports.kbdRecipe = Object.assign((0, core_1.resolveRecipe)(config), { config });
|
|
16
29
|
exports.default = config;
|
|
@@ -44,9 +44,14 @@ function LineChart({ data, height = 240, max, ticks = 5, color, area = true, dot
|
|
|
44
44
|
: "";
|
|
45
45
|
const summary = ariaLabel ??
|
|
46
46
|
`Line chart: ${data.map((d) => `${d.label} ${format(d.value)}`).join(", ")}`;
|
|
47
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, linechart_recipe_1.linechartRecipe)({ className }), ...rest,
|
|
47
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, linechart_recipe_1.linechartRecipe)({ className }), ...rest,
|
|
48
|
+
// merged, not assigned: written plainly this sits AFTER `{...rest}` and
|
|
49
|
+
// overwrites whatever style the consumer passed, so `style={{ maxWidth }}`
|
|
50
|
+
// on the chart did nothing at all. The consumer's wins on collision.
|
|
51
|
+
style: {
|
|
48
52
|
height,
|
|
49
53
|
"--crisp-linechart-yaxis-width": yAxisWidthValue,
|
|
54
|
+
...rest.style,
|
|
50
55
|
}, role: "img", "aria-label": summary, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-linechart-body", children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-linechart-yaxis", children: tickValues.map((t) => ((0, jsx_runtime_1.jsx)("span", { className: "crisp-linechart-ytick", style: { bottom: `${(t / top) * 100}%` }, children: format(t) }, t))) }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-linechart-plot", children: [tickValues.map((t) => ((0, jsx_runtime_1.jsx)("div", { className: "crisp-linechart-grid", style: { bottom: `${(t / top) * 100}%` } }, t))), pts.length > 1 && ((0, jsx_runtime_1.jsxs)("svg", { className: "crisp-linechart-svg", viewBox: "0 0 100 100", preserveAspectRatio: "none", "aria-hidden": "true", children: [area && (0, jsx_runtime_1.jsx)("path", { className: "crisp-linechart-area", d: areaPath }), (0, jsx_runtime_1.jsx)("polyline", { className: "crisp-linechart-line", points: line, style: { stroke: color } })] })), dots &&
|
|
51
56
|
pts.map((p, i) => ((0, jsx_runtime_1.jsx)("span", { className: "crisp-linechart-dot-html", style: {
|
|
52
57
|
left: `${p.x}%`,
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.skeletonRecipe = void 0;
|
|
3
|
+
exports.spec = exports.skeletonRecipe = void 0;
|
|
4
4
|
const core_1 = require("../../core");
|
|
5
5
|
const tokens_1 = require("../../tokens");
|
|
6
6
|
// A pulsing placeholder block for loading states.
|
|
7
|
-
const
|
|
7
|
+
const spec = (0, core_1.defineSpec)({
|
|
8
8
|
name: "skeleton",
|
|
9
|
-
globalCss:
|
|
10
|
-
base:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
globalCss: "@keyframes crisp-skeleton { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }",
|
|
10
|
+
base: {
|
|
11
|
+
display: "block",
|
|
12
|
+
background: `color-mix(in srgb, ${tokens_1.contract.fgPrimary} 8%, transparent)`,
|
|
13
|
+
borderRadius: tokens_1.contract.radius.md,
|
|
14
|
+
animation: "crisp-skeleton 1.4s ease-in-out infinite",
|
|
15
|
+
},
|
|
16
|
+
parts: [
|
|
17
|
+
{ selector: "&[data-circle]", decls: { borderRadius: tokens_1.contract.radius.full } },
|
|
18
|
+
],
|
|
15
19
|
});
|
|
20
|
+
exports.spec = spec;
|
|
21
|
+
const config = (0, core_1.specToRecipe)(spec);
|
|
16
22
|
exports.skeletonRecipe = (0, core_1.resolveRecipe)(config);
|
|
17
23
|
exports.default = config;
|
|
@@ -44,11 +44,15 @@ const table_recipe_1 = require("./table.recipe");
|
|
|
44
44
|
* `TableHeader`, `TableBody`, `TableFooter`, `TableRow`, `TableHead`,
|
|
45
45
|
* `TableCell`, and `TableCaption`.
|
|
46
46
|
*/
|
|
47
|
-
exports.Table = React.forwardRef(({ interactive, surface, className, wrapperClassName, scrollProps, children,
|
|
47
|
+
exports.Table = React.forwardRef(({ interactive, surface, className, wrapperClassName, scrollProps, children,
|
|
48
|
+
// on the root for the same reason as Textarea: the wrapper is the box a
|
|
49
|
+
// consumer sees and the scroll container they want to size. Native
|
|
50
|
+
// table attributes still reach the <table> below.
|
|
51
|
+
style, ...props }, ref) => ((0, jsx_runtime_1.jsx)("div", { className: (0, table_recipe_1.tableRecipe)({
|
|
48
52
|
interactive,
|
|
49
53
|
surface,
|
|
50
54
|
className: wrapperClassName,
|
|
51
|
-
}), children: (0, jsx_runtime_1.jsx)("div", { ...scrollProps, className: `crisp-table-scroll${scrollProps?.className ? ` ${scrollProps.className}` : ""}`, children: (0, jsx_runtime_1.jsx)("table", { ref: ref, className: className, ...props, children: children }) }) })));
|
|
55
|
+
}), style: style, children: (0, jsx_runtime_1.jsx)("div", { ...scrollProps, className: `crisp-table-scroll${scrollProps?.className ? ` ${scrollProps.className}` : ""}`, children: (0, jsx_runtime_1.jsx)("table", { ref: ref, className: className, ...props, children: children }) }) })));
|
|
52
56
|
exports.Table.displayName = "Table";
|
|
53
57
|
exports.TableHeader = React.forwardRef((props, ref) => (0, jsx_runtime_1.jsx)("thead", { ref: ref, ...props }));
|
|
54
58
|
exports.TableHeader.displayName = "TableHeader";
|
|
@@ -42,12 +42,19 @@ const textarea_recipe_1 = require("./textarea.recipe");
|
|
|
42
42
|
* `<textarea>` prop; pass `showCount` with `maxLength` to render a live
|
|
43
43
|
* character counter (which turns red if the value exceeds the limit).
|
|
44
44
|
*/
|
|
45
|
-
exports.Textarea = React.forwardRef(({ showCount, maxLength, className, wrapperClassName, value, defaultValue, onChange,
|
|
45
|
+
exports.Textarea = React.forwardRef(({ showCount, maxLength, className, wrapperClassName, value, defaultValue, onChange,
|
|
46
|
+
// `style` is pulled out and put on the ROOT, the way Input does it.
|
|
47
|
+
// Everything else belongs on the <textarea> -- id, name, form
|
|
48
|
+
// association, aria -- but `style` sizes the visual box, and the box is
|
|
49
|
+
// the root: it carries the focus ring (an ::after on the wrap) and the
|
|
50
|
+
// character counter. Left on the field, `style={{ maxWidth: 480 }}` gave
|
|
51
|
+
// a 480px control inside a full-width ring with the counter stranded.
|
|
52
|
+
style, ...props }, ref) => {
|
|
46
53
|
const initial = String(value ?? defaultValue ?? "").length;
|
|
47
54
|
const [count, setCount] = React.useState(initial);
|
|
48
55
|
const len = value !== undefined ? String(value).length : count;
|
|
49
56
|
const counted = showCount && maxLength != null;
|
|
50
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, textarea_recipe_1.textareaRecipe)({ className: wrapperClassName }), "data-counted": counted ? "" : undefined, children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-textarea-wrap", children: (0, jsx_runtime_1.jsx)("textarea", { ref: ref, className: `crisp-textarea-field${className ? ` ${className}` : ""}`, maxLength: maxLength, value: value, defaultValue: defaultValue, onChange: (e) => {
|
|
57
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, textarea_recipe_1.textareaRecipe)({ className: wrapperClassName }), style: style, "data-counted": counted ? "" : undefined, children: [(0, jsx_runtime_1.jsx)("span", { className: "crisp-textarea-wrap", children: (0, jsx_runtime_1.jsx)("textarea", { ref: ref, className: `crisp-textarea-field${className ? ` ${className}` : ""}`, maxLength: maxLength, value: value, defaultValue: defaultValue, onChange: (e) => {
|
|
51
58
|
if (value === undefined)
|
|
52
59
|
setCount(e.target.value.length);
|
|
53
60
|
onChange?.(e);
|
|
@@ -3,9 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.textareaRecipe = void 0;
|
|
4
4
|
const core_1 = require("../../core");
|
|
5
5
|
const tokens_1 = require("../../tokens");
|
|
6
|
-
// A multiline text field
|
|
7
|
-
//
|
|
8
|
-
//
|
|
6
|
+
// A multiline text field: an inset 1px ring (radius 8), 14px text, and an
|
|
7
|
+
// optional character counter pinned bottom-right (12px, muted). Focus rings
|
|
8
|
+
// the field brand.
|
|
9
|
+
//
|
|
10
|
+
// The inset is seed-design's, not Attio's -- the second deliberate divergence
|
|
11
|
+
// after the focus treatment. seed's text-input sets its inline inset to
|
|
12
|
+
// `$dimension.x3_5`, which rootage/dimension.yaml gives as **14px**, against
|
|
13
|
+
// the 10px this had. seed ships no textarea, so only the horizontal inset is
|
|
14
|
+
// theirs to copy; the vertical is derived from it: 10px above and below a
|
|
15
|
+
// 20px line makes a single-line box 40px tall, which is exactly seed's
|
|
16
|
+
// `$dimension.x10` medium field height. The counter's own inset moves to 14px
|
|
17
|
+
// with it, so it lines up with the text rather than sitting 4px inside it.
|
|
9
18
|
const config = (0, core_1.defineRecipe)({
|
|
10
19
|
name: "textarea",
|
|
11
20
|
base: `
|
|
@@ -13,7 +22,7 @@ const config = (0, core_1.defineRecipe)({
|
|
|
13
22
|
|
|
14
23
|
& .crisp-textarea-field {
|
|
15
24
|
box-sizing: border-box; display: block; width: 100%; min-height: 80px; resize: vertical;
|
|
16
|
-
margin: 0; padding: ${tokens_1.contract.space["
|
|
25
|
+
margin: 0; padding: ${tokens_1.contract.space["2.5"]} 14px; border: none; border-radius: ${tokens_1.contract.radius.md};
|
|
17
26
|
background: ${tokens_1.contract.bgSurface}; box-shadow: ${tokens_1.elevation.field};
|
|
18
27
|
font-family: inherit; font-size: ${tokens_1.contract.text.lg}; line-height: 20px; color: ${tokens_1.contract.fgPrimary};
|
|
19
28
|
outline: none; transition: box-shadow .15s ease;
|
|
@@ -35,7 +44,7 @@ const config = (0, core_1.defineRecipe)({
|
|
|
35
44
|
&[data-invalid] .crisp-textarea-wrap::after { border-color: ${tokens_1.contract.bgDanger}; }
|
|
36
45
|
&[data-invalid] .crisp-textarea-wrap:focus-within::after { border-color: ${tokens_1.contract.bgDanger}; }
|
|
37
46
|
&[data-counted] .crisp-textarea-field { padding-bottom: ${tokens_1.contract.space["5"]}; }
|
|
38
|
-
& .crisp-textarea-count { position: absolute; inset-inline-end:
|
|
47
|
+
& .crisp-textarea-count { position: absolute; inset-inline-end: 14px; bottom: ${tokens_1.contract.space["2.5"]}; font-size: ${tokens_1.contract.text.sm}; color: ${tokens_1.contract.fgMuted}; pointer-events: none; }
|
|
39
48
|
& .crisp-textarea-count[data-over] { color: ${tokens_1.contract.bgDanger}; }
|
|
40
49
|
`,
|
|
41
50
|
variants: {},
|
|
@@ -1,16 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.tooltipRecipe = void 0;
|
|
3
|
+
exports.spec = exports.tooltipRecipe = void 0;
|
|
4
4
|
const core_1 = require("../../core");
|
|
5
5
|
const tokens_1 = require("../../tokens");
|
|
6
6
|
// The floating bubble for a Tooltip — a dark hint chip. Applied to the
|
|
7
7
|
// portaled bubble itself (not a wrapper), so its styles survive the portal.
|
|
8
|
-
const
|
|
8
|
+
const spec = (0, core_1.defineSpec)({
|
|
9
9
|
name: "tooltip",
|
|
10
|
-
base:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
base: {
|
|
11
|
+
position: "fixed",
|
|
12
|
+
zIndex: 70,
|
|
13
|
+
boxSizing: "border-box",
|
|
14
|
+
pointerEvents: "none",
|
|
15
|
+
maxWidth: "260px",
|
|
16
|
+
padding: `${tokens_1.contract.space["1"]} ${tokens_1.contract.space["2"]}`,
|
|
17
|
+
borderRadius: tokens_1.contract.radius.sm,
|
|
18
|
+
background: "#20242c",
|
|
19
|
+
color: "#fff",
|
|
20
|
+
fontFamily: tokens_1.contract.font.sans,
|
|
21
|
+
fontSize: tokens_1.contract.text.sm,
|
|
22
|
+
fontWeight: tokens_1.contract.weight.medium,
|
|
23
|
+
lineHeight: "1.45",
|
|
24
|
+
boxShadow: "0 4px 14px -2px rgba(28,40,64,0.28), 0 0 0 1px rgba(255,255,255,0.04)",
|
|
25
|
+
opacity: 1,
|
|
26
|
+
transition: "opacity 0.12s ease",
|
|
27
|
+
},
|
|
28
|
+
parts: [
|
|
29
|
+
// An at-rule whose body is declarations rather than rules, so a part
|
|
30
|
+
// expresses it directly: the entry state the overlay animates from.
|
|
31
|
+
{ selector: "@starting-style", decls: { opacity: 0 } },
|
|
32
|
+
],
|
|
14
33
|
});
|
|
34
|
+
exports.spec = spec;
|
|
35
|
+
const config = (0, core_1.specToRecipe)(spec);
|
|
15
36
|
exports.tooltipRecipe = (0, core_1.resolveRecipe)(config);
|
|
16
37
|
exports.default = config;
|
|
@@ -392,7 +392,7 @@ function RecordPage({ record, columns, collection = "Records", labels, onBack, o
|
|
|
392
392
|
return ((0, jsx_runtime_1.jsx)("div", { className: "crisp-recordpage-panel", children: (0, jsx_runtime_1.jsx)(EmptyCard, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Folder, { size: 22, strokeWidth: 1.5 }), children: t.nothingHereYet }) }));
|
|
393
393
|
}
|
|
394
394
|
};
|
|
395
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, recordpage_recipe_1.recordpageRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-topbar", children: [(0, jsx_runtime_1.jsxs)("nav", { className: "crisp-recordpage-crumbs", "aria-label": t.breadcrumb, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-crumb", onClick: onBack, "aria-label": `Back to ${collection}`, children: collection }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-sep", children: "/" }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-name", children: name })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-actions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--ghost", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Sparkles, { size: 14, strokeWidth: 1.75, color: "var(--bg-brand-solid)" }), t.askAttio] }), onToggleFull && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", onClick: onToggleFull, "aria-label": full ? t.exitFullScreen : t.fullScreen, children: full ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Minimize2, { size: 15, strokeWidth: 1.75 })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Maximize2, { size: 15, strokeWidth: 1.75 })) })), (0, jsx_runtime_1.jsxs)(menu_1.Menu, { align: "end", "aria-label": t.recordActions, trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", "aria-label": t.recordActions, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreHorizontal, { size: 16, strokeWidth: 1.75 }) }), children: [(0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }), shortcut: "\u2318C", children: t.copyRecordLink }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 15, strokeWidth: 1.75 }), children: t.addToList }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }), onSelect: () => setFavorite((f) => !f), children: favorite ? t.removeFromFavourites : t.addToFavourites }), (0, jsx_runtime_1.jsx)(menu_1.MenuSeparator, {}), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { size: 15, strokeWidth: 1.75 }), danger: true, shortcut: "\u232B", children: t.deleteRecord })] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-body", children: [(0, jsx_runtime_1.jsxs)("aside", { className: "crisp-recordpage-details", style: { width: detailsW }, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-entity", children: [entity?.avatar ? ((0, jsx_runtime_1.jsx)("img", { className: "crisp-recordpage-entity-logo", src: entity.avatar, alt: "" })) : ((0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "lg", shape: "rounded", tone: "brand", children: name.charAt(0) })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-entity-name", children: name }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "aria-label": t.editRecord, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "data-active": favorite ? "" : undefined, "aria-pressed": favorite, onClick: () => setFavorite((f) => !f), "aria-label": favorite ? t.removeFromFavourites : t.addToFavourites, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-quickactions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-compose", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Mail, { size: 16, strokeWidth: 1.75 }), t.composeEmail] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.copyRecordLink, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.logANote, children: (0, jsx_runtime_1.jsx)(lucide_react_1.FileText, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.linkRecords, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Share2, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.createATask, children: (0, jsx_runtime_1.jsx)(lucide_react_1.SquareCheck, { size: 15, strokeWidth: 1.75 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-section", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-detailhead", children: [searchOpen ? ((0, jsx_runtime_1.jsx)("input", {
|
|
395
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, recordpage_recipe_1.recordpageRecipe)({ className }), ...rest, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-topbar", children: [(0, jsx_runtime_1.jsxs)("nav", { className: "crisp-recordpage-crumbs", "aria-label": t.breadcrumb, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-crumb", onClick: onBack, "aria-label": `Back to ${collection}`, children: collection }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-sep", children: "/" }), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-crumb-name", children: name })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-actions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--ghost", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Sparkles, { size: 14, strokeWidth: 1.75, color: "var(--crisp-bg-brand-solid)" }), t.askAttio] }), onToggleFull && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", onClick: onToggleFull, "aria-label": full ? t.exitFullScreen : t.fullScreen, children: full ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Minimize2, { size: 15, strokeWidth: 1.75 })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Maximize2, { size: 15, strokeWidth: 1.75 })) })), (0, jsx_runtime_1.jsxs)(menu_1.Menu, { align: "end", "aria-label": t.recordActions, trigger: (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-action crisp-recordpage-action--icon", "aria-label": t.recordActions, children: (0, jsx_runtime_1.jsx)(lucide_react_1.MoreHorizontal, { size: 16, strokeWidth: 1.75 }) }), children: [(0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }), shortcut: "\u2318C", children: t.copyRecordLink }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Plus, { size: 15, strokeWidth: 1.75 }), children: t.addToList }), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }), onSelect: () => setFavorite((f) => !f), children: favorite ? t.removeFromFavourites : t.addToFavourites }), (0, jsx_runtime_1.jsx)(menu_1.MenuSeparator, {}), (0, jsx_runtime_1.jsx)(menu_1.MenuItem, { icon: (0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { size: 15, strokeWidth: 1.75 }), danger: true, shortcut: "\u232B", children: t.deleteRecord })] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-body", children: [(0, jsx_runtime_1.jsxs)("aside", { className: "crisp-recordpage-details", style: { width: detailsW }, children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-entity", children: [entity?.avatar ? ((0, jsx_runtime_1.jsx)("img", { className: "crisp-recordpage-entity-logo", src: entity.avatar, alt: "" })) : ((0, jsx_runtime_1.jsx)(avatar_1.Avatar, { size: "lg", shape: "rounded", tone: "brand", children: name.charAt(0) })), (0, jsx_runtime_1.jsx)("span", { className: "crisp-recordpage-entity-name", children: name }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "aria-label": t.editRecord, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-entity-iconbtn", "data-active": favorite ? "" : undefined, "aria-pressed": favorite, onClick: () => setFavorite((f) => !f), "aria-label": favorite ? t.removeFromFavourites : t.addToFavourites, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Star, { size: 15, strokeWidth: 1.75 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-quickactions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-recordpage-compose", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Mail, { size: 16, strokeWidth: 1.75 }), t.composeEmail] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.copyRecordLink, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.logANote, children: (0, jsx_runtime_1.jsx)(lucide_react_1.FileText, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.linkRecords, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Share2, { size: 15, strokeWidth: 1.75 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "crisp-recordpage-quickbtn", "aria-label": t.createATask, children: (0, jsx_runtime_1.jsx)(lucide_react_1.SquareCheck, { size: 15, strokeWidth: 1.75 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-section", children: [(0, jsx_runtime_1.jsxs)("div", { className: "crisp-recordpage-detailhead", children: [searchOpen ? ((0, jsx_runtime_1.jsx)("input", {
|
|
396
396
|
// biome-ignore lint/a11y/noAutofocus: focusing the just-opened field search is expected
|
|
397
397
|
autoFocus: true, type: "text", className: "crisp-recordpage-fieldsearch", placeholder: t.searchPlaceholder, "aria-label": t.searchFields, value: fieldQuery, onChange: (e) => setFieldQuery(e.target.value), onKeyDown: (e) => {
|
|
398
398
|
if (e.key === "Escape") {
|
package/dist/command.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
.crisp-command {
|
|
2
|
-
display: contents; font-family: var(--crisp-font-sans)
|
|
2
|
+
display: contents; font-family: var(--crisp-font-sans);
|
|
3
3
|
& .crisp-command-content, & .crisp-command-card { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
|
|
4
4
|
& .crisp-command-backdrop { position: fixed; inset: 0; z-index: 50; background: transparent; }
|
|
5
5
|
& .crisp-command-positioner { position: fixed; inset: 0; z-index: 51; display: flex; align-items: flex-start; justify-content: center; padding: 15vh var(--crisp-space-4) var(--crisp-space-4); }
|
package/dist/command.layered.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
@layer crisp-components {
|
|
2
2
|
.crisp-command {
|
|
3
|
-
display: contents; font-family: var(--crisp-font-sans)
|
|
3
|
+
display: contents; font-family: var(--crisp-font-sans);
|
|
4
4
|
& .crisp-command-content, & .crisp-command-card { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
|
|
5
5
|
& .crisp-command-backdrop { position: fixed; inset: 0; z-index: 50; background: transparent; }
|
|
6
6
|
& .crisp-command-positioner { position: fixed; inset: 0; z-index: 51; display: flex; align-items: flex-start; justify-content: center; padding: 15vh var(--crisp-space-4) var(--crisp-space-4); }
|
|
@@ -1,15 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineSpec, resolveRecipe, specToRecipe } from "../../core/index.js";
|
|
2
2
|
import { contract as c } from "../../tokens/index.js";
|
|
3
3
|
// A row of overlapping avatars — each ringed in the surface colour so it reads
|
|
4
4
|
// against its neighbour, with a "+N" overflow chip.
|
|
5
|
-
const
|
|
5
|
+
const spec = defineSpec({
|
|
6
6
|
name: "avatargroup",
|
|
7
|
-
base:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
base: { display: "inline-flex", alignItems: "center" },
|
|
8
|
+
parts: [
|
|
9
|
+
{
|
|
10
|
+
slot: "member",
|
|
11
|
+
selector: "& > *",
|
|
12
|
+
decls: {
|
|
13
|
+
marginInlineStart: `-${c.space["2"]}`,
|
|
14
|
+
boxShadow: `0 0 0 2px ${c.bgSurface}`,
|
|
15
|
+
position: "relative",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
slot: "member",
|
|
20
|
+
selector: "& > *:first-child",
|
|
21
|
+
decls: { marginInlineStart: 0 },
|
|
22
|
+
},
|
|
23
|
+
],
|
|
13
24
|
});
|
|
25
|
+
const config = specToRecipe(spec);
|
|
14
26
|
export const avatargroupRecipe = resolveRecipe(config);
|
|
27
|
+
export { spec };
|
|
15
28
|
export default config;
|
|
@@ -31,9 +31,14 @@ export function BarChart({ data, height = 240, max, ticks = 5, color, format = (
|
|
|
31
31
|
: `max(34px, ${longestTickChars}ch + ${c.space["4"]})`;
|
|
32
32
|
const summary = ariaLabel ??
|
|
33
33
|
`Bar chart: ${data.map((d) => `${d.label} ${format(d.value)}`).join(", ")}`;
|
|
34
|
-
return (_jsxs("div", { className: barchartRecipe({ className }), ...rest,
|
|
34
|
+
return (_jsxs("div", { className: barchartRecipe({ className }), ...rest,
|
|
35
|
+
// merged, not assigned: written plainly this sits AFTER `{...rest}` and
|
|
36
|
+
// overwrites whatever style the consumer passed, so `style={{ maxWidth }}`
|
|
37
|
+
// on the chart did nothing at all. The consumer's wins on collision.
|
|
38
|
+
style: {
|
|
35
39
|
height,
|
|
36
40
|
"--crisp-barchart-yaxis-width": yAxisWidthValue,
|
|
41
|
+
...rest.style,
|
|
37
42
|
}, role: "img", "aria-label": summary, children: [_jsxs("div", { className: "crisp-barchart-body", children: [_jsx("div", { className: "crisp-barchart-yaxis", children: tickValues.map((t) => (_jsx("span", { className: "crisp-barchart-ytick", style: { bottom: `${(t / top) * 100}%` }, children: format(t) }, t))) }), _jsxs("div", { className: "crisp-barchart-plot", children: [tickValues.map((t) => (_jsx("div", { className: "crisp-barchart-grid", style: { bottom: `${(t / top) * 100}%` } }, t))), data.map((d) => (_jsx("div", { className: "crisp-barchart-col", children: _jsx("div", { className: "crisp-barchart-bar", "data-empty": d.value <= 0 ? "" : undefined, style: {
|
|
38
43
|
height: `${Math.max(0, (d.value / top) * 100)}%`,
|
|
39
44
|
background: color,
|
|
@@ -1,25 +1,58 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineSpec, resolveRecipe, specToRecipe } from "../../core/index.js";
|
|
2
2
|
import { contract as c } from "../../tokens/index.js";
|
|
3
3
|
// A 16px square checkbox measured from a record grid: r6, a subtle 1px
|
|
4
4
|
// inset ring when empty, brand fill + white check when on. The check is a
|
|
5
5
|
// data-URI SVG background so it renders reliably (input pseudo-content doesn't).
|
|
6
6
|
const CHECK = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 12 12' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 6.5 5 9l4.5-5'/%3E%3C/svg%3E\")";
|
|
7
|
-
const
|
|
7
|
+
const spec = defineSpec({
|
|
8
8
|
name: "checkbox",
|
|
9
|
-
base:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
9
|
+
base: {
|
|
10
|
+
appearance: "none",
|
|
11
|
+
WebkitAppearance: "none",
|
|
12
|
+
boxSizing: "border-box",
|
|
13
|
+
flexShrink: 0,
|
|
14
|
+
margin: 0,
|
|
15
|
+
width: "16px",
|
|
16
|
+
height: "16px",
|
|
17
|
+
border: "none",
|
|
18
|
+
borderRadius: c.radius.sm,
|
|
19
|
+
background: c.bgSurface,
|
|
20
|
+
boxShadow: `inset 0 0 0 1px color-mix(in srgb, ${c.fgPrimary} 9%, transparent)`,
|
|
21
|
+
cursor: "pointer",
|
|
22
|
+
transition: "background-color .12s, box-shadow .12s",
|
|
23
|
+
},
|
|
24
|
+
parts: [
|
|
25
|
+
{
|
|
26
|
+
selector: "&:hover",
|
|
27
|
+
decls: {
|
|
28
|
+
boxShadow: `inset 0 0 0 1px color-mix(in srgb, ${c.fgPrimary} 30%, transparent)`,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
selector: "&:checked, &:indeterminate",
|
|
33
|
+
decls: {
|
|
34
|
+
background: `${c.bgBrandSolid} center / 10px no-repeat`,
|
|
35
|
+
boxShadow: "none",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{ selector: "&:checked", decls: { backgroundImage: CHECK } },
|
|
39
|
+
{
|
|
40
|
+
selector: "&:indeterminate",
|
|
41
|
+
decls: {
|
|
42
|
+
backgroundImage: `linear-gradient(${c.fgOnBrand}, ${c.fgOnBrand})`,
|
|
43
|
+
backgroundSize: "8px 2px",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
selector: "&:focus-visible",
|
|
48
|
+
decls: {
|
|
49
|
+
outline: `2px solid ${c.bgBrandSolid}`,
|
|
50
|
+
outlineOffset: "1px",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
],
|
|
24
54
|
});
|
|
55
|
+
const config = specToRecipe(spec);
|
|
56
|
+
export const checkboxRecipe = Object.assign(resolveRecipe(config), { config });
|
|
57
|
+
export { spec };
|
|
25
58
|
export default config;
|
|
@@ -90,7 +90,13 @@ const DatePickerImplementation = React.forwardRef((props, forwardedRef) => {
|
|
|
90
90
|
}, ...mergeProps(api.rootProps, rootProps), "aria-label": rootAriaLabel, "aria-labelledby": ariaLabelledby, className: datepickerRecipe({
|
|
91
91
|
visibleRange: api.visibleRange,
|
|
92
92
|
className,
|
|
93
|
-
}),
|
|
93
|
+
}),
|
|
94
|
+
// merged: this sits after the spread above, so assigning it plainly
|
|
95
|
+
// dropped any style the consumer passed. Theirs wins on collision.
|
|
96
|
+
style: {
|
|
97
|
+
...styleOf({ height, minHeight, maxHeight }),
|
|
98
|
+
...rootProps?.style,
|
|
99
|
+
}, children: [api.visibleRange === "continuous" ? (_jsxs("div", { ref: api.refs.continuousScroll, ...api.continuousScrollProps, "data-date-picker-continuous-scroll": "", className: "crisp-datepicker-continuous-scroll", children: [_jsx(WeekdayRow, { api: api, semantic: false }), _jsxs("div", { className: "crisp-datepicker-continuous-content", children: [_jsx("div", { "aria-hidden": "true", className: "datepicker-continuous-spacer", style: { height: api.virtual.topHeight } }), api.months.map((month) => (_jsx(MonthView, { api: api, month: month, renderDateCellContent: renderDateCellContent, renderDateCellSupplement: renderDateCellSupplement, showWeekdays: false, showMonthLabel: true, monthRef: api.refs.continuousMonth(month.key) }, month.key))), _jsx("div", { "aria-hidden": "true", className: "datepicker-continuous-spacer", style: { height: api.virtual.bottomHeight } })] })] })) : (_jsxs(_Fragment, { children: [api.visibleRange !== "twoMonths" && _jsx(Header, { api: api }), _jsx("div", { "data-wheel-open": api.isWheelOpen && api.visibleRange !== "twoMonths"
|
|
94
100
|
? ""
|
|
95
101
|
: undefined, "aria-hidden": api.isWheelOpen && api.visibleRange !== "twoMonths"
|
|
96
102
|
? true
|