@crisp-ui-kit/crisp 0.44.0 → 0.45.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/chip.css ADDED
@@ -0,0 +1,27 @@
1
+ .crisp-chip {
2
+ display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding-inline: var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap;
3
+ }
4
+ .crisp-chip--tone_neutral {
5
+ background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle);
6
+ }
7
+ .crisp-chip--tone_brand {
8
+ background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-brand-solid) 30%, transparent);
9
+ }
10
+ .crisp-chip--tone_success {
11
+ background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-success) 30%, transparent);
12
+ }
13
+ .crisp-chip--tone_warning {
14
+ background: color-mix(in srgb, var(--crisp-bg-warning) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-warning) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-warning) 30%, transparent);
15
+ }
16
+ .crisp-chip--tone_danger {
17
+ background: color-mix(in srgb, var(--crisp-bg-danger) 15%, transparent); color: color-mix(in srgb, var(--crisp-bg-danger) 80%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-danger) 30%, transparent);
18
+ }
19
+ .crisp-chip--tone_purple {
20
+ background: color-mix(in srgb, var(--crisp-bg-purple) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-purple) 80%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-purple) 30%, transparent);
21
+ }
22
+ .crisp-chip--tone_cyan {
23
+ background: color-mix(in srgb, var(--crisp-bg-cyan) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-cyan) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-cyan) 30%, transparent);
24
+ }
25
+ .crisp-chip--tone_orange {
26
+ background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-orange) 30%, transparent);
27
+ }
package/dist/chip.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { RecipeFn } from "../core/types";
2
+
3
+ export interface ChipVariants {
4
+ tone?: "neutral" | "brand" | "success" | "warning" | "danger" | "purple" | "cyan" | "orange";
5
+ }
6
+
7
+ export declare const chipRecipe: RecipeFn<{ tone: { neutral: string; brand: string; success: string; warning: string; danger: string; purple: string; cyan: string; orange: string } }>;
@@ -0,0 +1,29 @@
1
+ @layer crisp-components {
2
+ .crisp-chip {
3
+ display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding-inline: var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap;
4
+ }
5
+ .crisp-chip--tone_neutral {
6
+ background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle);
7
+ }
8
+ .crisp-chip--tone_brand {
9
+ background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-brand-solid) 30%, transparent);
10
+ }
11
+ .crisp-chip--tone_success {
12
+ background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-success) 30%, transparent);
13
+ }
14
+ .crisp-chip--tone_warning {
15
+ background: color-mix(in srgb, var(--crisp-bg-warning) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-warning) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-warning) 30%, transparent);
16
+ }
17
+ .crisp-chip--tone_danger {
18
+ background: color-mix(in srgb, var(--crisp-bg-danger) 15%, transparent); color: color-mix(in srgb, var(--crisp-bg-danger) 80%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-danger) 30%, transparent);
19
+ }
20
+ .crisp-chip--tone_purple {
21
+ background: color-mix(in srgb, var(--crisp-bg-purple) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-purple) 80%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-purple) 30%, transparent);
22
+ }
23
+ .crisp-chip--tone_cyan {
24
+ background: color-mix(in srgb, var(--crisp-bg-cyan) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-cyan) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-cyan) 30%, transparent);
25
+ }
26
+ .crisp-chip--tone_orange {
27
+ background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-orange) 30%, transparent);
28
+ }
29
+ }
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.Chip = void 0;
37
+ const jsx_runtime_1 = require("react/jsx-runtime");
38
+ const React = __importStar(require("react"));
39
+ const core_1 = require("../../core");
40
+ const chip_recipe_1 = require("./chip.recipe");
41
+ /**
42
+ * A small pill — the same measured chip RecordsTable, RecordPanel and
43
+ * MultiSelect already draw as `.crisp-recordstable-tag`, exported standalone
44
+ * for surfaces that need one without a table or a fixed option set (e.g. a
45
+ * free-text tag list).
46
+ *
47
+ * This ships the measured body only. Attio's removable × on a chip needs a
48
+ * live, populated multi-value editor to measure against, and none was
49
+ * reachable this round (a person's "Email addresses" field was empty on the
50
+ * only record checked, and "Categories" removes via a checkbox toggle, not
51
+ * an inline ×) — so `Chip` has no `onRemove`/remove button yet. Add one once
52
+ * that surface can be measured; don't guess the icon, its hit target, or its
53
+ * spacing from the label.
54
+ */
55
+ exports.Chip = React.forwardRef(({ tone, className, asChild, children, ...props }, ref) => {
56
+ return ((0, jsx_runtime_1.jsx)(core_1.Primitive.span, { ref: ref, asChild: asChild, className: (0, chip_recipe_1.chipRecipe)({ tone, className }), ...props, children: children }));
57
+ });
58
+ exports.Chip.displayName = "Chip";
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.spec = exports.chipRecipe = void 0;
4
+ const core_1 = require("../../core");
5
+ const tokens_1 = require("../../tokens");
6
+ // The same measured pill RecordsTable/RecordPanel/MultiSelect already draw
7
+ // as ".crisp-recordstable-tag" (product/recordstable/recordstable.tag.ts's
8
+ // recordTagCss): 22px tall, `padding: 0 4px`, `border-radius: chip`,
9
+ // 14px/20px at weight 500, and a 1px inset ring in the tone's colour. That
10
+ // export is raw CSS written to be spliced under another component's own
11
+ // `&` root (RecordsTable/RecordPanel nest it inside their own recipe), so it
12
+ // can't be reused verbatim here — Chip's root IS the styled element, not a
13
+ // wrapper around one. The values below are transcribed from recordTagCss,
14
+ // not re-measured; keep the two in sync by hand if either changes.
15
+ const ring = (v, pct) => `inset 0 0 0 1px color-mix(in srgb, ${v} ${pct}%, transparent)`;
16
+ const soft = (v, pct) => `color-mix(in srgb, ${v} ${pct}%, transparent)`;
17
+ const onFg = (v, pct) => `color-mix(in srgb, ${v} ${pct}%, ${tokens_1.contract.fgPrimary})`;
18
+ const spec = (0, core_1.defineSpec)({
19
+ name: "chip",
20
+ base: {
21
+ display: "inline-flex",
22
+ alignItems: "center",
23
+ height: tokens_1.contract.size.chip,
24
+ paddingInline: tokens_1.contract.space["1"],
25
+ borderRadius: tokens_1.contract.radius.chip,
26
+ fontSize: tokens_1.contract.text.lg,
27
+ lineHeight: "20px",
28
+ fontWeight: tokens_1.contract.weight.medium,
29
+ whiteSpace: "nowrap",
30
+ },
31
+ variants: {
32
+ tone: {
33
+ neutral: {
34
+ background: soft(tokens_1.contract.fgPrimary, 6),
35
+ color: soft(tokens_1.contract.fgPrimary, 82),
36
+ boxShadow: `inset 0 0 0 1px ${tokens_1.contract.borderSubtle}`,
37
+ },
38
+ brand: {
39
+ background: soft(tokens_1.contract.bgBrandSolid, 14),
40
+ color: onFg(tokens_1.contract.bgBrandSolid, 82),
41
+ boxShadow: ring(tokens_1.contract.bgBrandSolid, 30),
42
+ },
43
+ success: {
44
+ background: soft(tokens_1.contract.bgSuccess, 16),
45
+ color: onFg(tokens_1.contract.bgSuccess, 78),
46
+ boxShadow: ring(tokens_1.contract.bgSuccess, 30),
47
+ },
48
+ warning: {
49
+ background: soft(tokens_1.contract.bgWarning, 18),
50
+ color: onFg(tokens_1.contract.bgWarning, 82),
51
+ boxShadow: ring(tokens_1.contract.bgWarning, 30),
52
+ },
53
+ danger: {
54
+ background: soft(tokens_1.contract.bgDanger, 15),
55
+ color: onFg(tokens_1.contract.bgDanger, 80),
56
+ boxShadow: ring(tokens_1.contract.bgDanger, 30),
57
+ },
58
+ purple: {
59
+ background: soft(tokens_1.contract.bgPurple, 16),
60
+ color: onFg(tokens_1.contract.bgPurple, 80),
61
+ boxShadow: ring(tokens_1.contract.bgPurple, 30),
62
+ },
63
+ cyan: {
64
+ background: soft(tokens_1.contract.bgCyan, 18),
65
+ color: onFg(tokens_1.contract.bgCyan, 82),
66
+ boxShadow: ring(tokens_1.contract.bgCyan, 30),
67
+ },
68
+ orange: {
69
+ background: soft(tokens_1.contract.bgOrange, 16),
70
+ color: onFg(tokens_1.contract.bgOrange, 82),
71
+ boxShadow: ring(tokens_1.contract.bgOrange, 30),
72
+ },
73
+ },
74
+ },
75
+ defaultVariants: { tone: "neutral" },
76
+ });
77
+ exports.spec = spec;
78
+ const config = (0, core_1.specToRecipe)(spec);
79
+ exports.chipRecipe = Object.assign((0, core_1.resolveRecipe)(config), { config });
80
+ exports.default = config;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.chipRecipe = exports.Chip = void 0;
4
+ var chip_1 = require("./chip");
5
+ Object.defineProperty(exports, "Chip", { enumerable: true, get: function () { return chip_1.Chip; } });
6
+ var chip_recipe_1 = require("./chip.recipe");
7
+ Object.defineProperty(exports, "chipRecipe", { enumerable: true, get: function () { return chip_recipe_1.chipRecipe; } });
package/dist/cjs/index.js CHANGED
@@ -29,6 +29,7 @@ __exportStar(require("./components/button"), exports);
29
29
  __exportStar(require("./components/callout"), exports);
30
30
  __exportStar(require("./components/card"), exports);
31
31
  __exportStar(require("./components/checkbox"), exports);
32
+ __exportStar(require("./components/chip"), exports);
32
33
  __exportStar(require("./components/columncalc"), exports);
33
34
  __exportStar(require("./components/contextmenu"), exports);
34
35
  __exportStar(require("./components/datatable"), exports);
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { Primitive } from "../../core/index.js";
4
+ import { chipRecipe } from "./chip.recipe.js";
5
+ /**
6
+ * A small pill — the same measured chip RecordsTable, RecordPanel and
7
+ * MultiSelect already draw as `.crisp-recordstable-tag`, exported standalone
8
+ * for surfaces that need one without a table or a fixed option set (e.g. a
9
+ * free-text tag list).
10
+ *
11
+ * This ships the measured body only. Attio's removable × on a chip needs a
12
+ * live, populated multi-value editor to measure against, and none was
13
+ * reachable this round (a person's "Email addresses" field was empty on the
14
+ * only record checked, and "Categories" removes via a checkbox toggle, not
15
+ * an inline ×) — so `Chip` has no `onRemove`/remove button yet. Add one once
16
+ * that surface can be measured; don't guess the icon, its hit target, or its
17
+ * spacing from the label.
18
+ */
19
+ export const Chip = React.forwardRef(({ tone, className, asChild, children, ...props }, ref) => {
20
+ return (_jsx(Primitive.span, { ref: ref, asChild: asChild, className: chipRecipe({ tone, className }), ...props, children: children }));
21
+ });
22
+ Chip.displayName = "Chip";
@@ -0,0 +1,77 @@
1
+ import { defineSpec, resolveRecipe, specToRecipe } from "../../core/index.js";
2
+ import { contract as c } from "../../tokens/index.js";
3
+ // The same measured pill RecordsTable/RecordPanel/MultiSelect already draw
4
+ // as ".crisp-recordstable-tag" (product/recordstable/recordstable.tag.ts's
5
+ // recordTagCss): 22px tall, `padding: 0 4px`, `border-radius: chip`,
6
+ // 14px/20px at weight 500, and a 1px inset ring in the tone's colour. That
7
+ // export is raw CSS written to be spliced under another component's own
8
+ // `&` root (RecordsTable/RecordPanel nest it inside their own recipe), so it
9
+ // can't be reused verbatim here — Chip's root IS the styled element, not a
10
+ // wrapper around one. The values below are transcribed from recordTagCss,
11
+ // not re-measured; keep the two in sync by hand if either changes.
12
+ const ring = (v, pct) => `inset 0 0 0 1px color-mix(in srgb, ${v} ${pct}%, transparent)`;
13
+ const soft = (v, pct) => `color-mix(in srgb, ${v} ${pct}%, transparent)`;
14
+ const onFg = (v, pct) => `color-mix(in srgb, ${v} ${pct}%, ${c.fgPrimary})`;
15
+ const spec = defineSpec({
16
+ name: "chip",
17
+ base: {
18
+ display: "inline-flex",
19
+ alignItems: "center",
20
+ height: c.size.chip,
21
+ paddingInline: c.space["1"],
22
+ borderRadius: c.radius.chip,
23
+ fontSize: c.text.lg,
24
+ lineHeight: "20px",
25
+ fontWeight: c.weight.medium,
26
+ whiteSpace: "nowrap",
27
+ },
28
+ variants: {
29
+ tone: {
30
+ neutral: {
31
+ background: soft(c.fgPrimary, 6),
32
+ color: soft(c.fgPrimary, 82),
33
+ boxShadow: `inset 0 0 0 1px ${c.borderSubtle}`,
34
+ },
35
+ brand: {
36
+ background: soft(c.bgBrandSolid, 14),
37
+ color: onFg(c.bgBrandSolid, 82),
38
+ boxShadow: ring(c.bgBrandSolid, 30),
39
+ },
40
+ success: {
41
+ background: soft(c.bgSuccess, 16),
42
+ color: onFg(c.bgSuccess, 78),
43
+ boxShadow: ring(c.bgSuccess, 30),
44
+ },
45
+ warning: {
46
+ background: soft(c.bgWarning, 18),
47
+ color: onFg(c.bgWarning, 82),
48
+ boxShadow: ring(c.bgWarning, 30),
49
+ },
50
+ danger: {
51
+ background: soft(c.bgDanger, 15),
52
+ color: onFg(c.bgDanger, 80),
53
+ boxShadow: ring(c.bgDanger, 30),
54
+ },
55
+ purple: {
56
+ background: soft(c.bgPurple, 16),
57
+ color: onFg(c.bgPurple, 80),
58
+ boxShadow: ring(c.bgPurple, 30),
59
+ },
60
+ cyan: {
61
+ background: soft(c.bgCyan, 18),
62
+ color: onFg(c.bgCyan, 82),
63
+ boxShadow: ring(c.bgCyan, 30),
64
+ },
65
+ orange: {
66
+ background: soft(c.bgOrange, 16),
67
+ color: onFg(c.bgOrange, 82),
68
+ boxShadow: ring(c.bgOrange, 30),
69
+ },
70
+ },
71
+ },
72
+ defaultVariants: { tone: "neutral" },
73
+ });
74
+ const config = specToRecipe(spec);
75
+ export const chipRecipe = Object.assign(resolveRecipe(config), { config });
76
+ export { spec };
77
+ export default config;
@@ -0,0 +1,2 @@
1
+ export { Chip } from "./chip.js";
2
+ export { chipRecipe } from "./chip.recipe.js";
package/dist/esm/index.js CHANGED
@@ -13,6 +13,7 @@ export * from "./components/button/index.js";
13
13
  export * from "./components/callout/index.js";
14
14
  export * from "./components/card/index.js";
15
15
  export * from "./components/checkbox/index.js";
16
+ export * from "./components/chip/index.js";
16
17
  export * from "./components/columncalc/index.js";
17
18
  export * from "./components/contextmenu/index.js";
18
19
  export * from "./components/datatable/index.js";
package/dist/styles.css CHANGED
@@ -428,6 +428,34 @@
428
428
  }
429
429
  }
430
430
 
431
+ .crisp-chip {
432
+ display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding-inline: var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap;
433
+ }
434
+ .crisp-chip--tone_neutral {
435
+ background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle);
436
+ }
437
+ .crisp-chip--tone_brand {
438
+ background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-brand-solid) 30%, transparent);
439
+ }
440
+ .crisp-chip--tone_success {
441
+ background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-success) 30%, transparent);
442
+ }
443
+ .crisp-chip--tone_warning {
444
+ background: color-mix(in srgb, var(--crisp-bg-warning) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-warning) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-warning) 30%, transparent);
445
+ }
446
+ .crisp-chip--tone_danger {
447
+ background: color-mix(in srgb, var(--crisp-bg-danger) 15%, transparent); color: color-mix(in srgb, var(--crisp-bg-danger) 80%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-danger) 30%, transparent);
448
+ }
449
+ .crisp-chip--tone_purple {
450
+ background: color-mix(in srgb, var(--crisp-bg-purple) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-purple) 80%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-purple) 30%, transparent);
451
+ }
452
+ .crisp-chip--tone_cyan {
453
+ background: color-mix(in srgb, var(--crisp-bg-cyan) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-cyan) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-cyan) 30%, transparent);
454
+ }
455
+ .crisp-chip--tone_orange {
456
+ background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-orange) 30%, transparent);
457
+ }
458
+
431
459
  .crisp-columncalc {
432
460
  display: flex; align-items: stretch; width: 100%; height: 100%; font-family: var(--crisp-font-sans); /* Menu wraps its trigger in a flex div that sizes to content, which would shrink the button back to its text. Make the wrapper fill too, so the whole cell stays clickable. */
433
461
  & .crisp-menu { width: 100%; height: 100%; }
@@ -429,6 +429,34 @@
429
429
  }
430
430
  }
431
431
 
432
+ .crisp-chip {
433
+ display: inline-flex; align-items: center; height: var(--crisp-size-chip); padding-inline: var(--crisp-space-1); border-radius: var(--crisp-radius-chip); font-size: var(--crisp-text-lg); line-height: 20px; font-weight: var(--crisp-weight-medium); white-space: nowrap;
434
+ }
435
+ .crisp-chip--tone_neutral {
436
+ background: color-mix(in srgb, var(--crisp-fg-primary) 6%, transparent); color: color-mix(in srgb, var(--crisp-fg-primary) 82%, transparent); box-shadow: inset 0 0 0 1px var(--crisp-border-subtle);
437
+ }
438
+ .crisp-chip--tone_brand {
439
+ background: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); color: color-mix(in srgb, var(--crisp-bg-brand-solid) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-brand-solid) 30%, transparent);
440
+ }
441
+ .crisp-chip--tone_success {
442
+ background: color-mix(in srgb, var(--crisp-bg-success) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-success) 78%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-success) 30%, transparent);
443
+ }
444
+ .crisp-chip--tone_warning {
445
+ background: color-mix(in srgb, var(--crisp-bg-warning) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-warning) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-warning) 30%, transparent);
446
+ }
447
+ .crisp-chip--tone_danger {
448
+ background: color-mix(in srgb, var(--crisp-bg-danger) 15%, transparent); color: color-mix(in srgb, var(--crisp-bg-danger) 80%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-danger) 30%, transparent);
449
+ }
450
+ .crisp-chip--tone_purple {
451
+ background: color-mix(in srgb, var(--crisp-bg-purple) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-purple) 80%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-purple) 30%, transparent);
452
+ }
453
+ .crisp-chip--tone_cyan {
454
+ background: color-mix(in srgb, var(--crisp-bg-cyan) 18%, transparent); color: color-mix(in srgb, var(--crisp-bg-cyan) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-cyan) 30%, transparent);
455
+ }
456
+ .crisp-chip--tone_orange {
457
+ background: color-mix(in srgb, var(--crisp-bg-orange) 16%, transparent); color: color-mix(in srgb, var(--crisp-bg-orange) 82%, var(--crisp-fg-primary)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--crisp-bg-orange) 30%, transparent);
458
+ }
459
+
432
460
  .crisp-columncalc {
433
461
  display: flex; align-items: stretch; width: 100%; height: 100%; font-family: var(--crisp-font-sans); /* Menu wraps its trigger in a flex div that sizes to content, which would shrink the button back to its text. Make the wrapper fill too, so the whole cell stays clickable. */
434
462
  & .crisp-menu { width: 100%; height: 100%; }
@@ -0,0 +1,47 @@
1
+ import * as React from "react";
2
+ import type { VariantProps } from "../../core";
3
+ import { chipRecipe } from "./chip.recipe";
4
+ export type ChipProps = React.ComponentPropsWithoutRef<"span"> & VariantProps<typeof chipRecipe> & {
5
+ asChild?: boolean;
6
+ };
7
+ /**
8
+ * A small pill — the same measured chip RecordsTable, RecordPanel and
9
+ * MultiSelect already draw as `.crisp-recordstable-tag`, exported standalone
10
+ * for surfaces that need one without a table or a fixed option set (e.g. a
11
+ * free-text tag list).
12
+ *
13
+ * This ships the measured body only. Attio's removable × on a chip needs a
14
+ * live, populated multi-value editor to measure against, and none was
15
+ * reachable this round (a person's "Email addresses" field was empty on the
16
+ * only record checked, and "Categories" removes via a checkbox toggle, not
17
+ * an inline ×) — so `Chip` has no `onRemove`/remove button yet. Add one once
18
+ * that surface can be measured; don't guess the icon, its hit target, or its
19
+ * spacing from the label.
20
+ */
21
+ export declare const Chip: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & VariantProps<import("../..").RecipeFn<{
22
+ readonly tone: {
23
+ readonly neutral: string;
24
+ readonly brand: string;
25
+ readonly success: string;
26
+ readonly warning: string;
27
+ readonly danger: string;
28
+ readonly purple: string;
29
+ readonly cyan: string;
30
+ readonly orange: string;
31
+ };
32
+ }> & {
33
+ config: import("../..").RecipeConfig<{
34
+ readonly tone: {
35
+ readonly neutral: string;
36
+ readonly brand: string;
37
+ readonly success: string;
38
+ readonly warning: string;
39
+ readonly danger: string;
40
+ readonly purple: string;
41
+ readonly cyan: string;
42
+ readonly orange: string;
43
+ };
44
+ }>;
45
+ }> & {
46
+ asChild?: boolean;
47
+ } & React.RefAttributes<HTMLSpanElement>>;
@@ -0,0 +1,100 @@
1
+ declare const spec: {
2
+ readonly name: "chip";
3
+ readonly base: {
4
+ readonly display: "inline-flex";
5
+ readonly alignItems: "center";
6
+ readonly height: `var(--${string})`;
7
+ readonly paddingInline: `var(--${string})`;
8
+ readonly borderRadius: `var(--${string})`;
9
+ readonly fontSize: `var(--${string})`;
10
+ readonly lineHeight: "20px";
11
+ readonly fontWeight: `var(--${string})`;
12
+ readonly whiteSpace: "nowrap";
13
+ };
14
+ readonly variants: {
15
+ readonly tone: {
16
+ readonly neutral: {
17
+ readonly background: string;
18
+ readonly color: string;
19
+ readonly boxShadow: `inset 0 0 0 1px var(--${string})`;
20
+ };
21
+ readonly brand: {
22
+ background: string;
23
+ color: string;
24
+ boxShadow: string;
25
+ };
26
+ readonly success: {
27
+ background: string;
28
+ color: string;
29
+ boxShadow: string;
30
+ };
31
+ readonly warning: {
32
+ background: string;
33
+ color: string;
34
+ boxShadow: string;
35
+ };
36
+ readonly danger: {
37
+ background: string;
38
+ color: string;
39
+ boxShadow: string;
40
+ };
41
+ readonly purple: {
42
+ background: string;
43
+ color: string;
44
+ boxShadow: string;
45
+ };
46
+ readonly cyan: {
47
+ background: string;
48
+ color: string;
49
+ boxShadow: string;
50
+ };
51
+ readonly orange: {
52
+ background: string;
53
+ color: string;
54
+ boxShadow: string;
55
+ };
56
+ };
57
+ };
58
+ readonly defaultVariants: {
59
+ readonly tone: "neutral";
60
+ };
61
+ };
62
+ declare const config: import("../..").RecipeConfig<{
63
+ readonly tone: {
64
+ readonly neutral: string;
65
+ readonly brand: string;
66
+ readonly success: string;
67
+ readonly warning: string;
68
+ readonly danger: string;
69
+ readonly purple: string;
70
+ readonly cyan: string;
71
+ readonly orange: string;
72
+ };
73
+ }>;
74
+ export declare const chipRecipe: import("../..").RecipeFn<{
75
+ readonly tone: {
76
+ readonly neutral: string;
77
+ readonly brand: string;
78
+ readonly success: string;
79
+ readonly warning: string;
80
+ readonly danger: string;
81
+ readonly purple: string;
82
+ readonly cyan: string;
83
+ readonly orange: string;
84
+ };
85
+ }> & {
86
+ config: import("../..").RecipeConfig<{
87
+ readonly tone: {
88
+ readonly neutral: string;
89
+ readonly brand: string;
90
+ readonly success: string;
91
+ readonly warning: string;
92
+ readonly danger: string;
93
+ readonly purple: string;
94
+ readonly cyan: string;
95
+ readonly orange: string;
96
+ };
97
+ }>;
98
+ };
99
+ export { spec };
100
+ export default config;
@@ -0,0 +1,2 @@
1
+ export { Chip, type ChipProps } from "./chip";
2
+ export { chipRecipe } from "./chip.recipe";
@@ -9,6 +9,7 @@ export * from "./components/button";
9
9
  export * from "./components/callout";
10
10
  export * from "./components/card";
11
11
  export * from "./components/checkbox";
12
+ export * from "./components/chip";
12
13
  export * from "./components/columncalc";
13
14
  export * from "./components/contextmenu";
14
15
  export * from "./components/datatable";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crisp-ui-kit/crisp",
3
- "version": "0.44.0",
3
+ "version": "0.45.0",
4
4
  "description": "A lean React design system, measured pixel-for-pixel from Attio.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -88,6 +88,11 @@
88
88
  "import": "./dist/esm/components/checkbox/index.js",
89
89
  "require": "./dist/cjs/components/checkbox/index.js"
90
90
  },
91
+ "./chip": {
92
+ "types": "./dist/types/components/chip/index.d.ts",
93
+ "import": "./dist/esm/components/chip/index.js",
94
+ "require": "./dist/cjs/components/chip/index.js"
95
+ },
91
96
  "./columncalc": {
92
97
  "types": "./dist/types/components/columncalc/index.d.ts",
93
98
  "import": "./dist/esm/components/columncalc/index.js",