@crisp-ui-kit/crisp 0.32.0 → 0.33.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/cjs/components/badge/badge.recipe.js +83 -24
- package/dist/cjs/components/datatable/datatable.js +11 -3
- package/dist/cjs/components/divider/divider.recipe.js +20 -8
- package/dist/cjs/components/progress/progress.recipe.js +50 -10
- package/dist/cjs/components/spinner/spinner.recipe.js +15 -7
- package/dist/cjs/core/index.js +4 -1
- package/dist/cjs/core/spec.js +71 -0
- package/dist/esm/components/badge/badge.recipe.js +83 -24
- package/dist/esm/components/datatable/datatable.js +11 -3
- package/dist/esm/components/divider/divider.recipe.js +20 -8
- package/dist/esm/components/progress/progress.recipe.js +50 -10
- package/dist/esm/components/spinner/spinner.recipe.js +15 -7
- package/dist/esm/core/index.js +1 -0
- package/dist/esm/core/spec.js +66 -0
- package/dist/types/components/badge/badge.d.ts +26 -26
- package/dist/types/components/badge/badge.recipe.d.ts +169 -45
- package/dist/types/components/divider/divider.recipe.d.ts +26 -2
- package/dist/types/components/progress/progress.recipe.d.ts +49 -2
- package/dist/types/components/spinner/spinner.recipe.d.ts +17 -2
- package/dist/types/core/index.d.ts +1 -0
- package/dist/types/core/spec.d.ts +83 -0
- package/package.json +4 -1
|
@@ -1,60 +1,119 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.badgeRecipe = void 0;
|
|
3
|
+
exports.spec = exports.badgeRecipe = void 0;
|
|
4
4
|
const core_1 = require("../../core");
|
|
5
5
|
const tokens_1 = require("../../tokens");
|
|
6
|
-
const
|
|
6
|
+
const ring = (v, pct) => `inset 0 0 0 1px color-mix(in srgb, ${v} ${pct}%, transparent)`;
|
|
7
|
+
const soft = (v, pct) => `color-mix(in srgb, ${v} ${pct}%, transparent)`;
|
|
8
|
+
const spec = (0, core_1.defineSpec)({
|
|
7
9
|
name: "badge",
|
|
8
|
-
base:
|
|
9
|
-
|
|
10
|
+
base: {
|
|
11
|
+
display: "inline-flex",
|
|
12
|
+
alignItems: "center",
|
|
13
|
+
justifyContent: "center",
|
|
14
|
+
gap: tokens_1.contract.space["1"],
|
|
15
|
+
fontFamily: tokens_1.contract.font.sans,
|
|
16
|
+
fontWeight: tokens_1.contract.weight.medium,
|
|
17
|
+
letterSpacing: "-0.1px",
|
|
18
|
+
whiteSpace: "nowrap",
|
|
19
|
+
},
|
|
20
|
+
parts: [
|
|
21
|
+
{
|
|
22
|
+
slot: "dot",
|
|
23
|
+
selector: "& .crisp-badge-dot",
|
|
24
|
+
decls: {
|
|
25
|
+
width: "6px",
|
|
26
|
+
height: "6px",
|
|
27
|
+
flexShrink: 0,
|
|
28
|
+
borderRadius: tokens_1.contract.radius.full,
|
|
29
|
+
background: "currentColor",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
],
|
|
10
33
|
variants: {
|
|
11
34
|
tone: {
|
|
12
|
-
neutral:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
35
|
+
neutral: {
|
|
36
|
+
background: tokens_1.contract.bgRaised,
|
|
37
|
+
color: tokens_1.contract.fgMuted,
|
|
38
|
+
boxShadow: `inset 0 0 0 1px ${tokens_1.contract.borderDefault}`,
|
|
39
|
+
},
|
|
40
|
+
brand: {
|
|
41
|
+
background: soft(tokens_1.contract.bgBrandSolid, 14),
|
|
42
|
+
color: tokens_1.contract.bgBrandSolid,
|
|
43
|
+
boxShadow: ring(tokens_1.contract.bgBrandSolid, 30),
|
|
44
|
+
},
|
|
45
|
+
success: {
|
|
46
|
+
background: soft(tokens_1.contract.bgSuccess, 14),
|
|
47
|
+
color: tokens_1.contract.bgSuccess,
|
|
48
|
+
boxShadow: ring(tokens_1.contract.bgSuccess, 30),
|
|
49
|
+
},
|
|
50
|
+
warning: {
|
|
51
|
+
background: soft(tokens_1.contract.bgWarning, 16),
|
|
52
|
+
color: tokens_1.contract.bgWarning,
|
|
53
|
+
boxShadow: ring(tokens_1.contract.bgWarning, 32),
|
|
54
|
+
},
|
|
55
|
+
danger: {
|
|
56
|
+
background: soft(tokens_1.contract.bgDanger, 14),
|
|
57
|
+
color: tokens_1.contract.bgDanger,
|
|
58
|
+
boxShadow: ring(tokens_1.contract.bgDanger, 30),
|
|
59
|
+
},
|
|
17
60
|
},
|
|
18
61
|
size: {
|
|
19
|
-
small:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
62
|
+
small: {
|
|
63
|
+
height: "16px",
|
|
64
|
+
paddingInline: tokens_1.contract.space["1.5"],
|
|
65
|
+
fontSize: tokens_1.contract.text.xs,
|
|
66
|
+
borderRadius: tokens_1.contract.radius.sm,
|
|
67
|
+
},
|
|
68
|
+
medium: {
|
|
69
|
+
height: "20px",
|
|
70
|
+
paddingInline: tokens_1.contract.space["2"],
|
|
71
|
+
fontSize: tokens_1.contract.text.sm,
|
|
72
|
+
borderRadius: tokens_1.contract.radius.sm,
|
|
73
|
+
},
|
|
74
|
+
large: {
|
|
75
|
+
height: tokens_1.contract.size.chip,
|
|
76
|
+
paddingInline: "9px",
|
|
77
|
+
fontSize: tokens_1.contract.text.lg,
|
|
78
|
+
borderRadius: tokens_1.contract.radius.chip,
|
|
79
|
+
},
|
|
26
80
|
},
|
|
81
|
+
variant: { soft: {}, solid: {} },
|
|
27
82
|
},
|
|
28
83
|
defaultVariants: { tone: "neutral", size: "medium", variant: "soft" },
|
|
29
84
|
compoundVariants: [
|
|
30
85
|
{
|
|
31
86
|
variant: "solid",
|
|
32
87
|
tone: "brand",
|
|
33
|
-
|
|
88
|
+
decls: {
|
|
89
|
+
background: tokens_1.contract.bgBrandSolid,
|
|
90
|
+
color: tokens_1.contract.fgOnBrand,
|
|
91
|
+
boxShadow: "none",
|
|
92
|
+
},
|
|
34
93
|
},
|
|
35
94
|
{
|
|
36
95
|
variant: "solid",
|
|
37
96
|
tone: "success",
|
|
38
|
-
|
|
97
|
+
decls: { background: tokens_1.contract.bgSuccess, color: tokens_1.contract.fgOnTone, boxShadow: "none" },
|
|
39
98
|
},
|
|
40
99
|
{
|
|
41
100
|
variant: "solid",
|
|
42
101
|
tone: "warning",
|
|
43
|
-
|
|
102
|
+
decls: { background: tokens_1.contract.bgWarning, color: tokens_1.contract.fgOnTone, boxShadow: "none" },
|
|
44
103
|
},
|
|
45
104
|
{
|
|
46
105
|
variant: "solid",
|
|
47
106
|
tone: "danger",
|
|
48
|
-
|
|
107
|
+
decls: { background: tokens_1.contract.bgDanger, color: tokens_1.contract.fgOnTone, boxShadow: "none" },
|
|
49
108
|
},
|
|
50
109
|
{
|
|
51
110
|
variant: "solid",
|
|
52
111
|
tone: "neutral",
|
|
53
|
-
|
|
112
|
+
decls: { background: tokens_1.contract.fgMuted, color: tokens_1.contract.bgSurface, boxShadow: "none" },
|
|
54
113
|
},
|
|
55
114
|
],
|
|
56
115
|
});
|
|
57
|
-
exports.
|
|
58
|
-
|
|
59
|
-
});
|
|
116
|
+
exports.spec = spec;
|
|
117
|
+
const config = (0, core_1.specToRecipe)(spec);
|
|
118
|
+
exports.badgeRecipe = Object.assign((0, core_1.resolveRecipe)(config), { config });
|
|
60
119
|
exports.default = config;
|
|
@@ -402,21 +402,29 @@ function DataTable({ columns: columnsProp, data, selectable = false, selectedIds
|
|
|
402
402
|
// sticky attrs for the leading column(s): grip col (index -2) + selection
|
|
403
403
|
// col (-1) + first data column (0). Each offsets by whatever leading
|
|
404
404
|
// columns come before it, so the group stays contiguous when scrolled.
|
|
405
|
+
// `insetInlineStart`, never `left`: the offset pins the column to the
|
|
406
|
+
// LEADING edge, which is the right one under `dir="rtl"`. A physical `left`
|
|
407
|
+
// pins to the trailing edge instead, and the column scrolls out of view the
|
|
408
|
+
// moment sticky would have engaged (#285). RecordsTable does the same job in
|
|
409
|
+
// CSS and has used the logical property since #91 -- this offset is computed
|
|
410
|
+
// here rather than in a recipe, which is why that sweep could not reach it.
|
|
405
411
|
const stickyCol = (index) => {
|
|
406
412
|
if (!stickyFirst)
|
|
407
413
|
return {};
|
|
408
414
|
if (showGrip && index === -2)
|
|
409
|
-
return { "data-sticky": "", style: {
|
|
415
|
+
return { "data-sticky": "", style: { insetInlineStart: 0 } };
|
|
410
416
|
if (selectable && index === -1)
|
|
411
417
|
return {
|
|
412
418
|
"data-sticky": "",
|
|
413
|
-
style: {
|
|
419
|
+
style: { insetInlineStart: showGrip ? GRIP_W : 0 },
|
|
414
420
|
};
|
|
415
421
|
if (index === 0)
|
|
416
422
|
return {
|
|
417
423
|
"data-sticky": "",
|
|
418
424
|
"data-sticky-edge": "",
|
|
419
|
-
style: {
|
|
425
|
+
style: {
|
|
426
|
+
insetInlineStart: (showGrip ? GRIP_W : 0) + (selectable ? CHECK_W : 0),
|
|
427
|
+
},
|
|
420
428
|
};
|
|
421
429
|
return {};
|
|
422
430
|
};
|
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.dividerRecipe = void 0;
|
|
3
|
+
exports.spec = exports.dividerRecipe = void 0;
|
|
4
4
|
const core_1 = require("../../core");
|
|
5
5
|
const tokens_1 = require("../../tokens");
|
|
6
6
|
// A hairline separator — horizontal (default) or vertical.
|
|
7
|
-
const
|
|
7
|
+
const spec = (0, core_1.defineSpec)({
|
|
8
8
|
name: "divider",
|
|
9
|
-
base:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
base: {
|
|
10
|
+
flexShrink: 0,
|
|
11
|
+
border: "none",
|
|
12
|
+
margin: 0,
|
|
13
|
+
background: tokens_1.contract.borderSubtle,
|
|
14
|
+
},
|
|
15
|
+
parts: [
|
|
16
|
+
{
|
|
17
|
+
selector: '&[data-orientation="horizontal"]',
|
|
18
|
+
decls: { width: "100%", height: "1px" },
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
selector: '&[data-orientation="vertical"]',
|
|
22
|
+
decls: { width: "1px", alignSelf: "stretch", minHeight: "1em" },
|
|
23
|
+
},
|
|
24
|
+
],
|
|
15
25
|
});
|
|
26
|
+
exports.spec = spec;
|
|
27
|
+
const config = (0, core_1.specToRecipe)(spec);
|
|
16
28
|
exports.dividerRecipe = (0, core_1.resolveRecipe)(config);
|
|
17
29
|
exports.default = config;
|
|
@@ -1,20 +1,60 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.progressRecipe = void 0;
|
|
3
|
+
exports.spec = exports.progressRecipe = void 0;
|
|
4
4
|
const core_1 = require("../../core");
|
|
5
5
|
const tokens_1 = require("../../tokens");
|
|
6
6
|
// A progress indicator — a continuous brand-filled track, or a segmented row of
|
|
7
7
|
// pills (a "Getting started 3/6" bar).
|
|
8
|
-
const
|
|
8
|
+
const spec = (0, core_1.defineSpec)({
|
|
9
9
|
name: "progress",
|
|
10
|
-
base:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
base: {
|
|
11
|
+
display: "block",
|
|
12
|
+
boxSizing: "border-box",
|
|
13
|
+
height: "6px",
|
|
14
|
+
borderRadius: tokens_1.contract.radius.full,
|
|
15
|
+
background: `color-mix(in srgb, ${tokens_1.contract.fgPrimary} 8%, transparent)`,
|
|
16
|
+
overflow: "hidden",
|
|
17
|
+
},
|
|
18
|
+
parts: [
|
|
19
|
+
{
|
|
20
|
+
slot: "fill",
|
|
21
|
+
selector: "& .crisp-progress-fill",
|
|
22
|
+
decls: {
|
|
23
|
+
display: "block",
|
|
24
|
+
height: "100%",
|
|
25
|
+
borderRadius: tokens_1.contract.radius.full,
|
|
26
|
+
background: tokens_1.contract.bgBrandSolid,
|
|
27
|
+
transition: "width 0.25s ease",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
selector: "&[data-segmented]",
|
|
32
|
+
decls: {
|
|
33
|
+
display: "flex",
|
|
34
|
+
gap: tokens_1.contract.space["1"],
|
|
35
|
+
background: "transparent",
|
|
36
|
+
overflow: "visible",
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
slot: "seg",
|
|
41
|
+
selector: "&[data-segmented] .crisp-progress-seg",
|
|
42
|
+
decls: {
|
|
43
|
+
flex: 1,
|
|
44
|
+
height: "100%",
|
|
45
|
+
borderRadius: tokens_1.contract.radius.full,
|
|
46
|
+
background: `color-mix(in srgb, ${tokens_1.contract.fgPrimary} 8%, transparent)`,
|
|
47
|
+
transition: "background 0.2s",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
slot: "seg",
|
|
52
|
+
selector: "&[data-segmented] .crisp-progress-seg[data-filled]",
|
|
53
|
+
decls: { background: tokens_1.contract.bgBrandSolid },
|
|
54
|
+
},
|
|
55
|
+
],
|
|
18
56
|
});
|
|
57
|
+
exports.spec = spec;
|
|
58
|
+
const config = (0, core_1.specToRecipe)(spec);
|
|
19
59
|
exports.progressRecipe = (0, core_1.resolveRecipe)(config);
|
|
20
60
|
exports.default = config;
|
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.spinnerRecipe = void 0;
|
|
3
|
+
exports.spec = exports.spinnerRecipe = void 0;
|
|
4
4
|
const core_1 = require("../../core");
|
|
5
5
|
const tokens_1 = require("../../tokens");
|
|
6
6
|
// A spinning ring loading indicator.
|
|
7
|
-
const
|
|
7
|
+
const spec = (0, core_1.defineSpec)({
|
|
8
8
|
name: "spinner",
|
|
9
|
-
globalCss:
|
|
10
|
-
base:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
globalCss: "@keyframes crisp-spin { to { transform: rotate(360deg); } }",
|
|
10
|
+
base: {
|
|
11
|
+
display: "inline-block",
|
|
12
|
+
boxSizing: "border-box",
|
|
13
|
+
width: "16px",
|
|
14
|
+
height: "16px",
|
|
15
|
+
borderRadius: tokens_1.contract.radius.full,
|
|
16
|
+
border: `2px solid color-mix(in srgb, ${tokens_1.contract.fgPrimary} 15%, transparent)`,
|
|
17
|
+
borderTopColor: tokens_1.contract.fgMuted,
|
|
18
|
+
animation: "crisp-spin 0.6s linear infinite",
|
|
19
|
+
},
|
|
14
20
|
});
|
|
21
|
+
exports.spec = spec;
|
|
22
|
+
const config = (0, core_1.specToRecipe)(spec);
|
|
15
23
|
exports.spinnerRecipe = (0, core_1.resolveRecipe)(config);
|
|
16
24
|
exports.default = config;
|
package/dist/cjs/core/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.usePrefersReducedMotion = exports.useLabelAssociation = exports.useFormReset = exports.useFocusAfterRemoval = exports.resolveRecipe = exports.Primitive = exports.placeFloating = exports.formValueStyle = exports.isRtlElement = exports.withDescribedBy = exports.defineRecipe = exports.cx = void 0;
|
|
17
|
+
exports.usePrefersReducedMotion = exports.useLabelAssociation = exports.useFormReset = exports.useFocusAfterRemoval = exports.specToRecipe = exports.defineSpec = exports.resolveRecipe = exports.Primitive = exports.placeFloating = exports.formValueStyle = exports.isRtlElement = exports.withDescribedBy = exports.defineRecipe = exports.cx = void 0;
|
|
18
18
|
var cx_1 = require("./cx");
|
|
19
19
|
Object.defineProperty(exports, "cx", { enumerable: true, get: function () { return cx_1.cx; } });
|
|
20
20
|
var define_1 = require("./define");
|
|
@@ -32,6 +32,9 @@ Object.defineProperty(exports, "Primitive", { enumerable: true, get: function ()
|
|
|
32
32
|
var resolve_1 = require("./resolve");
|
|
33
33
|
Object.defineProperty(exports, "resolveRecipe", { enumerable: true, get: function () { return resolve_1.resolveRecipe; } });
|
|
34
34
|
__exportStar(require("./rtl"), exports);
|
|
35
|
+
var spec_1 = require("./spec");
|
|
36
|
+
Object.defineProperty(exports, "defineSpec", { enumerable: true, get: function () { return spec_1.defineSpec; } });
|
|
37
|
+
Object.defineProperty(exports, "specToRecipe", { enumerable: true, get: function () { return spec_1.specToRecipe; } });
|
|
35
38
|
var use_focus_after_removal_1 = require("./use-focus-after-removal");
|
|
36
39
|
Object.defineProperty(exports, "useFocusAfterRemoval", { enumerable: true, get: function () { return use_focus_after_removal_1.useFocusAfterRemoval; } });
|
|
37
40
|
var use_form_reset_1 = require("./use-form-reset");
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.declsToCss = declsToCss;
|
|
4
|
+
exports.defineSpec = defineSpec;
|
|
5
|
+
exports.specToRecipe = specToRecipe;
|
|
6
|
+
const kebab = (p) => p.startsWith("--") ? p : p.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
7
|
+
/** `{ flexShrink: 0 }` -> `flex-shrink: 0;`, in insertion order. */
|
|
8
|
+
function declsToCss(decls) {
|
|
9
|
+
return Object.entries(decls)
|
|
10
|
+
.map(([prop, value]) => `${kebab(prop)}: ${value};`)
|
|
11
|
+
.join(" ");
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* `const` type parameter, not a plain `ComponentSpec` return: widening the
|
|
15
|
+
* variant keys here loses the literal union that `VariantProps<typeof recipe>`
|
|
16
|
+
* hands a component, and `BadgeProps["tone"]` silently degrades from
|
|
17
|
+
* `"neutral" | "brand" | …` to `string`. That is a public API regression that
|
|
18
|
+
* typechecks everywhere except at the call sites it was meant to protect.
|
|
19
|
+
*/
|
|
20
|
+
function defineSpec(spec) {
|
|
21
|
+
return spec;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Compile a spec into the RecipeConfig the existing pipeline already takes, so
|
|
25
|
+
* nothing downstream — the CSS generator, the d.ts generator, `resolveRecipe`,
|
|
26
|
+
* the spec guards — has to know a spec exists. That is what keeps the
|
|
27
|
+
* conversion provable: `dist/` must not move, and CI's
|
|
28
|
+
* `git diff --exit-code dist/` is the gate.
|
|
29
|
+
*
|
|
30
|
+
* The formatting here is not cosmetic freedom. It reproduces exactly what the
|
|
31
|
+
* hand-written template strings emit — root declarations space-joined, each
|
|
32
|
+
* nested rule on its own line indented four spaces — because any other choice
|
|
33
|
+
* rewrites every committed stylesheet and buries the conversion's real diff.
|
|
34
|
+
*/
|
|
35
|
+
function specToRecipe(spec) {
|
|
36
|
+
const root = declsToCss(spec.base);
|
|
37
|
+
const nested = (spec.parts ?? []).map((p) => `${p.selector} { ${declsToCss(p.decls)} }`);
|
|
38
|
+
const base = nested.length ? `${root}\n ${nested.join("\n ")}` : root;
|
|
39
|
+
// A variant value compiles the same way the root does: declarations first,
|
|
40
|
+
// then any nested rules it contributes, so a variant that restyles a part
|
|
41
|
+
// (Badge's solid dot) stays in the variant rather than leaking into base.
|
|
42
|
+
const compileValue = (v) => {
|
|
43
|
+
const decls = "decls" in v ? v.decls : v;
|
|
44
|
+
const nestedParts = "decls" in v ? (v.parts ?? []) : [];
|
|
45
|
+
const head = declsToCss(decls);
|
|
46
|
+
if (!nestedParts.length)
|
|
47
|
+
return head;
|
|
48
|
+
const tail = nestedParts
|
|
49
|
+
.map((p) => `${p.selector} { ${declsToCss(p.decls)} }`)
|
|
50
|
+
.join("\n ");
|
|
51
|
+
return head ? `${head}\n ${tail}` : tail;
|
|
52
|
+
};
|
|
53
|
+
const variants = {};
|
|
54
|
+
for (const [name, values] of Object.entries(spec.variants ?? {})) {
|
|
55
|
+
variants[name] = {};
|
|
56
|
+
for (const [value, v] of Object.entries(values)) {
|
|
57
|
+
variants[name][value] = compileValue(v);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
name: spec.name,
|
|
62
|
+
base,
|
|
63
|
+
variants: variants,
|
|
64
|
+
defaultVariants: (spec.defaultVariants ?? {}),
|
|
65
|
+
compoundVariants: (spec.compoundVariants ?? []).map(({ decls, ...sel }) => ({
|
|
66
|
+
...sel,
|
|
67
|
+
css: declsToCss(decls),
|
|
68
|
+
})),
|
|
69
|
+
...(spec.globalCss ? { globalCss: spec.globalCss } : {}),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -1,57 +1,116 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineSpec, resolveRecipe, specToRecipe } from "../../core/index.js";
|
|
2
2
|
import { contract as c } from "../../tokens/index.js";
|
|
3
|
-
const
|
|
3
|
+
const ring = (v, pct) => `inset 0 0 0 1px color-mix(in srgb, ${v} ${pct}%, transparent)`;
|
|
4
|
+
const soft = (v, pct) => `color-mix(in srgb, ${v} ${pct}%, transparent)`;
|
|
5
|
+
const spec = defineSpec({
|
|
4
6
|
name: "badge",
|
|
5
|
-
base:
|
|
6
|
-
|
|
7
|
+
base: {
|
|
8
|
+
display: "inline-flex",
|
|
9
|
+
alignItems: "center",
|
|
10
|
+
justifyContent: "center",
|
|
11
|
+
gap: c.space["1"],
|
|
12
|
+
fontFamily: c.font.sans,
|
|
13
|
+
fontWeight: c.weight.medium,
|
|
14
|
+
letterSpacing: "-0.1px",
|
|
15
|
+
whiteSpace: "nowrap",
|
|
16
|
+
},
|
|
17
|
+
parts: [
|
|
18
|
+
{
|
|
19
|
+
slot: "dot",
|
|
20
|
+
selector: "& .crisp-badge-dot",
|
|
21
|
+
decls: {
|
|
22
|
+
width: "6px",
|
|
23
|
+
height: "6px",
|
|
24
|
+
flexShrink: 0,
|
|
25
|
+
borderRadius: c.radius.full,
|
|
26
|
+
background: "currentColor",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
],
|
|
7
30
|
variants: {
|
|
8
31
|
tone: {
|
|
9
|
-
neutral:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
32
|
+
neutral: {
|
|
33
|
+
background: c.bgRaised,
|
|
34
|
+
color: c.fgMuted,
|
|
35
|
+
boxShadow: `inset 0 0 0 1px ${c.borderDefault}`,
|
|
36
|
+
},
|
|
37
|
+
brand: {
|
|
38
|
+
background: soft(c.bgBrandSolid, 14),
|
|
39
|
+
color: c.bgBrandSolid,
|
|
40
|
+
boxShadow: ring(c.bgBrandSolid, 30),
|
|
41
|
+
},
|
|
42
|
+
success: {
|
|
43
|
+
background: soft(c.bgSuccess, 14),
|
|
44
|
+
color: c.bgSuccess,
|
|
45
|
+
boxShadow: ring(c.bgSuccess, 30),
|
|
46
|
+
},
|
|
47
|
+
warning: {
|
|
48
|
+
background: soft(c.bgWarning, 16),
|
|
49
|
+
color: c.bgWarning,
|
|
50
|
+
boxShadow: ring(c.bgWarning, 32),
|
|
51
|
+
},
|
|
52
|
+
danger: {
|
|
53
|
+
background: soft(c.bgDanger, 14),
|
|
54
|
+
color: c.bgDanger,
|
|
55
|
+
boxShadow: ring(c.bgDanger, 30),
|
|
56
|
+
},
|
|
14
57
|
},
|
|
15
58
|
size: {
|
|
16
|
-
small:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
59
|
+
small: {
|
|
60
|
+
height: "16px",
|
|
61
|
+
paddingInline: c.space["1.5"],
|
|
62
|
+
fontSize: c.text.xs,
|
|
63
|
+
borderRadius: c.radius.sm,
|
|
64
|
+
},
|
|
65
|
+
medium: {
|
|
66
|
+
height: "20px",
|
|
67
|
+
paddingInline: c.space["2"],
|
|
68
|
+
fontSize: c.text.sm,
|
|
69
|
+
borderRadius: c.radius.sm,
|
|
70
|
+
},
|
|
71
|
+
large: {
|
|
72
|
+
height: c.size.chip,
|
|
73
|
+
paddingInline: "9px",
|
|
74
|
+
fontSize: c.text.lg,
|
|
75
|
+
borderRadius: c.radius.chip,
|
|
76
|
+
},
|
|
23
77
|
},
|
|
78
|
+
variant: { soft: {}, solid: {} },
|
|
24
79
|
},
|
|
25
80
|
defaultVariants: { tone: "neutral", size: "medium", variant: "soft" },
|
|
26
81
|
compoundVariants: [
|
|
27
82
|
{
|
|
28
83
|
variant: "solid",
|
|
29
84
|
tone: "brand",
|
|
30
|
-
|
|
85
|
+
decls: {
|
|
86
|
+
background: c.bgBrandSolid,
|
|
87
|
+
color: c.fgOnBrand,
|
|
88
|
+
boxShadow: "none",
|
|
89
|
+
},
|
|
31
90
|
},
|
|
32
91
|
{
|
|
33
92
|
variant: "solid",
|
|
34
93
|
tone: "success",
|
|
35
|
-
|
|
94
|
+
decls: { background: c.bgSuccess, color: c.fgOnTone, boxShadow: "none" },
|
|
36
95
|
},
|
|
37
96
|
{
|
|
38
97
|
variant: "solid",
|
|
39
98
|
tone: "warning",
|
|
40
|
-
|
|
99
|
+
decls: { background: c.bgWarning, color: c.fgOnTone, boxShadow: "none" },
|
|
41
100
|
},
|
|
42
101
|
{
|
|
43
102
|
variant: "solid",
|
|
44
103
|
tone: "danger",
|
|
45
|
-
|
|
104
|
+
decls: { background: c.bgDanger, color: c.fgOnTone, boxShadow: "none" },
|
|
46
105
|
},
|
|
47
106
|
{
|
|
48
107
|
variant: "solid",
|
|
49
108
|
tone: "neutral",
|
|
50
|
-
|
|
109
|
+
decls: { background: c.fgMuted, color: c.bgSurface, boxShadow: "none" },
|
|
51
110
|
},
|
|
52
111
|
],
|
|
53
112
|
});
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
113
|
+
const config = specToRecipe(spec);
|
|
114
|
+
export const badgeRecipe = Object.assign(resolveRecipe(config), { config });
|
|
115
|
+
export { spec };
|
|
57
116
|
export default config;
|
|
@@ -366,21 +366,29 @@ export function DataTable({ columns: columnsProp, data, selectable = false, sele
|
|
|
366
366
|
// sticky attrs for the leading column(s): grip col (index -2) + selection
|
|
367
367
|
// col (-1) + first data column (0). Each offsets by whatever leading
|
|
368
368
|
// columns come before it, so the group stays contiguous when scrolled.
|
|
369
|
+
// `insetInlineStart`, never `left`: the offset pins the column to the
|
|
370
|
+
// LEADING edge, which is the right one under `dir="rtl"`. A physical `left`
|
|
371
|
+
// pins to the trailing edge instead, and the column scrolls out of view the
|
|
372
|
+
// moment sticky would have engaged (#285). RecordsTable does the same job in
|
|
373
|
+
// CSS and has used the logical property since #91 -- this offset is computed
|
|
374
|
+
// here rather than in a recipe, which is why that sweep could not reach it.
|
|
369
375
|
const stickyCol = (index) => {
|
|
370
376
|
if (!stickyFirst)
|
|
371
377
|
return {};
|
|
372
378
|
if (showGrip && index === -2)
|
|
373
|
-
return { "data-sticky": "", style: {
|
|
379
|
+
return { "data-sticky": "", style: { insetInlineStart: 0 } };
|
|
374
380
|
if (selectable && index === -1)
|
|
375
381
|
return {
|
|
376
382
|
"data-sticky": "",
|
|
377
|
-
style: {
|
|
383
|
+
style: { insetInlineStart: showGrip ? GRIP_W : 0 },
|
|
378
384
|
};
|
|
379
385
|
if (index === 0)
|
|
380
386
|
return {
|
|
381
387
|
"data-sticky": "",
|
|
382
388
|
"data-sticky-edge": "",
|
|
383
|
-
style: {
|
|
389
|
+
style: {
|
|
390
|
+
insetInlineStart: (showGrip ? GRIP_W : 0) + (selectable ? CHECK_W : 0),
|
|
391
|
+
},
|
|
384
392
|
};
|
|
385
393
|
return {};
|
|
386
394
|
};
|
|
@@ -1,14 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineSpec, resolveRecipe, specToRecipe } from "../../core/index.js";
|
|
2
2
|
import { contract as c } from "../../tokens/index.js";
|
|
3
3
|
// A hairline separator — horizontal (default) or vertical.
|
|
4
|
-
const
|
|
4
|
+
const spec = defineSpec({
|
|
5
5
|
name: "divider",
|
|
6
|
-
base:
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
base: {
|
|
7
|
+
flexShrink: 0,
|
|
8
|
+
border: "none",
|
|
9
|
+
margin: 0,
|
|
10
|
+
background: c.borderSubtle,
|
|
11
|
+
},
|
|
12
|
+
parts: [
|
|
13
|
+
{
|
|
14
|
+
selector: '&[data-orientation="horizontal"]',
|
|
15
|
+
decls: { width: "100%", height: "1px" },
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
selector: '&[data-orientation="vertical"]',
|
|
19
|
+
decls: { width: "1px", alignSelf: "stretch", minHeight: "1em" },
|
|
20
|
+
},
|
|
21
|
+
],
|
|
12
22
|
});
|
|
23
|
+
const config = specToRecipe(spec);
|
|
13
24
|
export const dividerRecipe = resolveRecipe(config);
|
|
25
|
+
export { spec };
|
|
14
26
|
export default config;
|