@crisp-ui-kit/crisp 0.57.0 → 0.57.1

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.
Files changed (96) hide show
  1. package/dist/accentpicker.css +5 -0
  2. package/dist/accentpicker.d.ts +7 -0
  3. package/dist/accentpicker.layered.css +7 -0
  4. package/dist/avatar.css +1 -1
  5. package/dist/avatar.layered.css +1 -1
  6. package/dist/badge.css +2 -2
  7. package/dist/badge.layered.css +2 -2
  8. package/dist/button.css +3 -3
  9. package/dist/button.layered.css +3 -3
  10. package/dist/cjs/components/accentpicker/accentpicker.js +66 -0
  11. package/dist/cjs/components/accentpicker/accentpicker.recipe.js +25 -0
  12. package/dist/cjs/components/accentpicker/index.js +7 -0
  13. package/dist/cjs/components/avatar/avatar.recipe.js +4 -1
  14. package/dist/cjs/components/badge/badge.recipe.js +16 -2
  15. package/dist/cjs/components/button/button.recipe.js +16 -6
  16. package/dist/cjs/components/input/input.js +2 -2
  17. package/dist/cjs/components/input/input.recipe.js +8 -0
  18. package/dist/cjs/components/multiselect/multiselect.js +1 -1
  19. package/dist/cjs/components/multiselect/multiselect.recipe.js +12 -3
  20. package/dist/cjs/components/progress/progress.js +21 -4
  21. package/dist/cjs/components/progress/progress.recipe.js +30 -0
  22. package/dist/cjs/components/select/select.js +2 -2
  23. package/dist/cjs/components/select/select.recipe.js +32 -5
  24. package/dist/cjs/components/text/text.recipe.js +8 -7
  25. package/dist/cjs/components/textarea/textarea.js +3 -2
  26. package/dist/cjs/components/textarea/textarea.recipe.js +2 -1
  27. package/dist/cjs/components/textlink/textlink.recipe.js +6 -3
  28. package/dist/cjs/index.js +1 -0
  29. package/dist/cjs/product/recordpage/recordpage.js +46 -5
  30. package/dist/cjs/tokens/palette.js +79 -25
  31. package/dist/cjs/tokens/scale.js +1 -0
  32. package/dist/cjs/tokens/semantic.js +24 -0
  33. package/dist/esm/components/accentpicker/accentpicker.js +30 -0
  34. package/dist/esm/components/accentpicker/accentpicker.recipe.js +22 -0
  35. package/dist/esm/components/accentpicker/index.js +2 -0
  36. package/dist/esm/components/avatar/avatar.recipe.js +4 -1
  37. package/dist/esm/components/badge/badge.recipe.js +16 -2
  38. package/dist/esm/components/button/button.recipe.js +16 -6
  39. package/dist/esm/components/input/input.js +3 -3
  40. package/dist/esm/components/input/input.recipe.js +8 -0
  41. package/dist/esm/components/multiselect/multiselect.js +1 -1
  42. package/dist/esm/components/multiselect/multiselect.recipe.js +12 -3
  43. package/dist/esm/components/progress/progress.js +22 -5
  44. package/dist/esm/components/progress/progress.recipe.js +30 -0
  45. package/dist/esm/components/select/select.js +2 -2
  46. package/dist/esm/components/select/select.recipe.js +32 -5
  47. package/dist/esm/components/text/text.recipe.js +8 -7
  48. package/dist/esm/components/textarea/textarea.js +3 -2
  49. package/dist/esm/components/textarea/textarea.recipe.js +2 -1
  50. package/dist/esm/components/textlink/textlink.recipe.js +6 -3
  51. package/dist/esm/index.js +1 -0
  52. package/dist/esm/product/recordpage/recordpage.js +47 -6
  53. package/dist/esm/tokens/palette.js +79 -25
  54. package/dist/esm/tokens/scale.js +1 -0
  55. package/dist/esm/tokens/semantic.js +24 -0
  56. package/dist/input.css +7 -0
  57. package/dist/input.layered.css +7 -0
  58. package/dist/multiselect.css +4 -0
  59. package/dist/multiselect.d.ts +2 -2
  60. package/dist/multiselect.layered.css +4 -0
  61. package/dist/native/tokens.d.ts +1 -1
  62. package/dist/native/tokens.js +33 -22
  63. package/dist/progress.css +3 -0
  64. package/dist/progress.layered.css +3 -0
  65. package/dist/select.css +22 -2
  66. package/dist/select.d.ts +2 -2
  67. package/dist/select.layered.css +22 -2
  68. package/dist/styles.css +71 -23
  69. package/dist/styles.layered.css +71 -23
  70. package/dist/text.css +1 -1
  71. package/dist/text.layered.css +1 -1
  72. package/dist/textarea.css +2 -1
  73. package/dist/textarea.layered.css +2 -1
  74. package/dist/textlink.css +2 -2
  75. package/dist/textlink.layered.css +2 -2
  76. package/dist/tokens.css +18 -11
  77. package/dist/tokens.json +33 -22
  78. package/dist/types/components/accentpicker/accentpicker.d.ts +23 -0
  79. package/dist/types/components/accentpicker/accentpicker.recipe.d.ts +3 -0
  80. package/dist/types/components/accentpicker/index.d.ts +2 -0
  81. package/dist/types/components/button/button.recipe.d.ts +2 -2
  82. package/dist/types/components/input/input.d.ts +12 -0
  83. package/dist/types/components/multiselect/multiselect.d.ts +4 -3
  84. package/dist/types/components/multiselect/multiselect.recipe.d.ts +3 -0
  85. package/dist/types/components/progress/progress.d.ts +16 -4
  86. package/dist/types/components/progress/progress.recipe.d.ts +22 -0
  87. package/dist/types/components/select/select.d.ts +6 -5
  88. package/dist/types/components/select/select.recipe.d.ts +3 -0
  89. package/dist/types/components/textarea/textarea.d.ts +16 -0
  90. package/dist/types/index.d.ts +1 -0
  91. package/dist/types/product/recordpage/recordpage.d.ts +37 -1
  92. package/dist/types/tokens/contract.d.ts +4 -1
  93. package/dist/types/tokens/palette.d.ts +19 -11
  94. package/dist/types/tokens/scale.d.ts +1 -0
  95. package/dist/types/tokens/semantic.d.ts +15 -0
  96. package/package.json +6 -1
@@ -27,14 +27,16 @@
27
27
  font-display: swap;
28
28
  }
29
29
  :root {
30
- --crisp-bg-brand-solid: #266df0;
31
- --crisp-bg-brand-solid-pressed: #1f5fd6;
30
+ --crisp-bg-brand-solid: #0298d9;
31
+ --crisp-bg-brand-solid-pressed: #0283bb;
32
+ --crisp-bg-brand-contrast: #0278ac;
33
+ --crisp-fg-brand-contrast: #0278ac;
32
34
  --crisp-fg-on-brand: #ffffff;
33
35
  --crisp-fg-on-tone: #101112;
34
36
  --crisp-bg-surface: #ffffff;
35
- --crisp-bg-raised: #f4f4f5;
37
+ --crisp-bg-raised: #f7f8f9;
36
38
  --crisp-bg-surface-muted: #f6f7f7;
37
- --crisp-border-default: #e4e4e7;
39
+ --crisp-border-default: #dcdee3;
38
40
  --crisp-border-subtle: #eeeff1;
39
41
  --crisp-border-dropzone: #e6e7ea;
40
42
  --crisp-border-divider: #e6e7ea;
@@ -56,9 +58,9 @@
56
58
  --crisp-shadow-popover3: rgba(24,41,75,0.16);
57
59
  --crisp-fg-primary: #101112;
58
60
  --crisp-fg-muted: #71717a;
59
- --crisp-bg-danger: #e5484d;
60
- --crisp-bg-danger-solid: #ba2525;
61
- --crisp-fg-danger: #eb3b3b;
61
+ --crisp-bg-danger: #fa342c;
62
+ --crisp-bg-danger-solid: #ca1d13;
63
+ --crisp-fg-danger: #fa342c;
62
64
  --crisp-stroke-field-focus: #1a1c20;
63
65
  --crisp-fg-disabled: #d1d3d8;
64
66
  --crisp-bg-neutral-weak: #f3f4f5;
@@ -67,8 +69,9 @@
67
69
  --crisp-fg-neutral-subtle: #868b94;
68
70
  --crisp-fg-neutral-muted: #555d6d;
69
71
  --crisp-stroke-focus-ring: #1e82eb;
70
- --crisp-bg-success: #1f9d57;
71
- --crisp-bg-warning: #b5730f;
72
+ --crisp-bg-success: #079171;
73
+ --crisp-bg-warning: #9b7821;
74
+ --crisp-bg-warning-solid: #fbdc65;
72
75
  --crisp-bg-orange: #f97514;
73
76
  --crisp-bg-cyan: #00b9eb;
74
77
  --crisp-bg-purple: #9b69ff;
@@ -95,8 +98,10 @@
95
98
  }
96
99
 
97
100
  [data-theme="dark"] {
98
- --crisp-bg-brand-solid: #266df0;
99
- --crisp-bg-brand-solid-pressed: #1f5fd6;
101
+ --crisp-bg-brand-solid: #0298d9;
102
+ --crisp-bg-brand-solid-pressed: #0283bb;
103
+ --crisp-bg-brand-contrast: #0278ac;
104
+ --crisp-fg-brand-contrast: #0278ac;
100
105
  --crisp-fg-on-brand: #ffffff;
101
106
  --crisp-fg-on-tone: #101112;
102
107
  --crisp-bg-surface: #0a0a0a;
@@ -137,6 +142,7 @@
137
142
  --crisp-stroke-focus-ring: #5e98fe;
138
143
  --crisp-bg-success: #2ea968;
139
144
  --crisp-bg-warning: #e0982a;
145
+ --crisp-bg-warning-solid: #e0982a;
140
146
  --crisp-bg-orange: #f97514;
141
147
  --crisp-bg-cyan: #00b9eb;
142
148
  --crisp-bg-purple: #9b69ff;
@@ -175,6 +181,7 @@
175
181
  --crisp-space-1-5: 6px;
176
182
  --crisp-space-2-5: 10px;
177
183
  --crisp-space-3-5: 14px;
184
+ --crisp-radius-xs: 4px;
178
185
  --crisp-radius-chip: 7px;
179
186
  --crisp-radius-sm: 6px;
180
187
  --crisp-radius-md: 8px;
@@ -208,6 +215,12 @@
208
215
  }
209
216
 
210
217
  @layer crisp-components {
218
+ .crisp-accentpicker {
219
+ display: flex; gap: var(--crisp-space-2);
220
+ & .crisp-accentpicker-swatch { box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0; margin: 0; border-radius: var(--crisp-radius-full); border: 1px solid transparent; background: none; font-family: inherit; cursor: pointer; }
221
+ & .crisp-accentpicker-swatch:focus-visible { outline: 2px solid var(--crisp-bg-brand-solid); outline-offset: 2px; }
222
+ }
223
+
211
224
  .crisp-accordion {
212
225
  display: flex; flex-direction: column; font-family: var(--crisp-font-sans);
213
226
  & .crisp-accordion-item { border-bottom: 1px solid var(--crisp-border-subtle); }
@@ -256,7 +269,7 @@
256
269
  background: var(--crisp-bg-raised); color: var(--crisp-fg-neutral-muted); box-shadow: inset 0 0 0 1px var(--crisp-border-default);
257
270
  }
258
271
  .crisp-avatar--tone_brand {
259
- background: var(--crisp-bg-brand-solid); color: #fff;
272
+ background: var(--crisp-bg-brand-contrast); color: #fff;
260
273
  }
261
274
  .crisp-avatar--tone_orange {
262
275
  background: var(--crisp-bg-orange); color: #fff;
@@ -315,13 +328,13 @@
315
328
 
316
329
  }
317
330
  .crisp-badge--compound_0 {
318
- background: var(--crisp-bg-brand-solid); color: var(--crisp-fg-on-brand); box-shadow: none;
331
+ background: var(--crisp-bg-brand-contrast); color: var(--crisp-fg-on-brand); box-shadow: none;
319
332
  }
320
333
  .crisp-badge--compound_1 {
321
334
  background: var(--crisp-bg-success); color: var(--crisp-fg-on-tone); box-shadow: none;
322
335
  }
323
336
  .crisp-badge--compound_2 {
324
- background: var(--crisp-bg-warning); color: var(--crisp-fg-on-tone); box-shadow: none;
337
+ background: var(--crisp-bg-warning-solid); color: var(--crisp-fg-on-tone); box-shadow: none;
325
338
  }
326
339
  .crisp-badge--compound_3 {
327
340
  background: var(--crisp-bg-danger); color: var(--crisp-fg-on-tone); box-shadow: none;
@@ -396,9 +409,9 @@
396
409
  &:disabled { opacity: 0.5; cursor: not-allowed; }
397
410
  }
398
411
  .crisp-button--intent_primary {
399
- background: var(--crisp-bg-brand-solid); color: var(--crisp-fg-on-brand); box-shadow: inset 0 0 0 1px rgba(0,0,0,0.06), 0 2px 4px -2px rgba(38,109,240,0.12), 0 3px 6px -2px rgba(38,109,240,0.08);
400
- &:hover { background: var(--crisp-bg-brand-solid-pressed); }
401
- &:active { background: var(--crisp-bg-brand-solid-pressed); }
412
+ background: var(--crisp-bg-brand-contrast); color: var(--crisp-fg-on-brand); box-shadow: inset 0 0 0 1px rgba(0,0,0,0.06), 0 2px 4px -2px rgba(38,109,240,0.12), 0 3px 6px -2px rgba(38,109,240,0.08);
413
+ &:hover { filter: brightness(0.96); }
414
+ &:active { filter: brightness(0.92); }
402
415
  }
403
416
  .crisp-button--intent_neutral {
404
417
  background: var(--crisp-bg-surface); color: var(--crisp-fg-primary); box-shadow: inset 0 0 0 1px var(--crisp-ring-neutral), 0 0 2px rgba(28,40,64,0.18), 0 1px 3px rgba(0,0,0,0.04);
@@ -1386,6 +1399,13 @@
1386
1399
  & .crisp-input-value::placeholder { color: var(--crisp-fg-muted); }
1387
1400
  & .crisp-input-value:disabled { opacity: 0.5; cursor: not-allowed; }
1388
1401
  &:has(.crisp-input-value:disabled) { opacity: 1; }
1402
+ /* crisp#634: measured live on Attio's own Settings > Profile read-only
1403
+ primary-email field -- a tinted field, not just muted text, driven off
1404
+ the native `readOnly` attribute. `ringField` (rgba(0,0,0,.06)) is an
1405
+ exact match for the measured ring; the 2%-fgPrimary tint reuses the
1406
+ same color-mix idiom every other soft crisp surface already uses. */
1407
+ &[data-readonly] { background: color-mix(in srgb, var(--crisp-fg-primary) 2%, transparent); box-shadow: inset 0 0 0 1px var(--crisp-ring-field); }
1408
+ & .crisp-input-suffix { flex-shrink: 0; margin-inline-start: var(--crisp-space-1); }
1389
1409
  }
1390
1410
  .crisp-input--size_sm {
1391
1411
  height: var(--crisp-size-row); border-radius: var(--crisp-radius-md);
@@ -1561,6 +1581,10 @@
1561
1581
  & .crisp-multiselect-chevron { flex-shrink: 0; color: var(--crisp-fg-neutral-muted); transition: transform .1s cubic-bezier(.35,0,.35,1); }
1562
1582
  & .crisp-multiselect-trigger[data-open] .crisp-multiselect-chevron { transform: rotate(180deg); transition-duration: .15s; }
1563
1583
  }
1584
+ .crisp-multiselect--size_small {
1585
+ & .crisp-multiselect-trigger { min-height: var(--crisp-size-menuRow); border-radius: var(--crisp-radius-md); gap: var(--crisp-space-1); padding: var(--crisp-space-0-5) var(--crisp-space-1-5) var(--crisp-space-0-5) var(--crisp-space-2); }
1586
+ & .crisp-multiselect-chevron { width: var(--crisp-size-icon); height: var(--crisp-size-icon); }
1587
+ }
1564
1588
  .crisp-multiselect--size_medium {
1565
1589
  & .crisp-multiselect-trigger { min-height: var(--crisp-size-selectTriggerMd); border-radius: var(--crisp-radius-md); gap: var(--crisp-space-2); padding: var(--crisp-space-1) var(--crisp-space-3-5); }
1566
1590
  & .crisp-multiselect-chevron { width: var(--crisp-size-icon); height: var(--crisp-size-icon); }
@@ -1619,6 +1643,9 @@
1619
1643
  &[data-segmented] { display: flex; gap: var(--crisp-space-1); background: transparent; overflow: visible; }
1620
1644
  &[data-segmented] .crisp-progress-seg { flex: 1; height: 100%; border-radius: var(--crisp-radius-full); background: color-mix(in srgb, var(--crisp-fg-primary) 8%, transparent); transition: background 0.2s; }
1621
1645
  &[data-segmented] .crisp-progress-seg[data-filled] { background: var(--crisp-bg-brand-solid); }
1646
+ &[data-variant="circular"] { display: inline-flex; height: auto; border-radius: 0; background: transparent; overflow: visible; }
1647
+ & .crisp-progress-circle-track { stroke: color-mix(in srgb, var(--crisp-bg-brand-solid) 14%, transparent); }
1648
+ & .crisp-progress-circle-fill { stroke: var(--crisp-bg-brand-solid); transition: stroke-dashoffset 0.25s ease; }
1622
1649
  }
1623
1650
 
1624
1651
  @media (prefers-reduced-motion: reduce) {
@@ -1777,9 +1804,19 @@
1777
1804
  }
1778
1805
  .crisp-select-listbox[data-up] { transform-origin: bottom left; }
1779
1806
  .crisp-select-listbox { @starting-style { opacity: 0; transform: scale(0.95); } }
1780
- .crisp-select-search { display: flex; align-items: center; gap: var(--crisp-space-2); height: 34px; flex-shrink: 0; margin: calc(-1 * var(--crisp-space-2)) calc(-1 * var(--crisp-space-2)) var(--crisp-space-2); padding: 0 var(--crisp-space-2-5); border-bottom: 1px solid var(--crisp-border-subtle); color: var(--crisp-fg-neutral-muted); }
1807
+ /* Composed from @seed-design/rootage's text-input.yaml
1808
+ (variant=outline,size=medium) -- seed's Select has no search field of
1809
+ its own to resolve this from (see the file header), so this reuses
1810
+ the SAME tokens #867 already resolved for the trigger at this size:
1811
+ minHeight x10 (var(--crisp-size-selectTriggerMd)), paddingX x3_5
1812
+ (var(--crisp-space-3-5)), gap x2 (var(--crisp-space-2)), cornerRadius r2
1813
+ (var(--crisp-radius-md)), strokeColor stroke.neutral-weak
1814
+ (var(--crisp-stroke-select-trigger)) -- a real bordered field sitting flush
1815
+ inside the listbox's own 8px padding, replacing the old bare
1816
+ 34px/no-border/bleeds-to-the-edge strip (crisp/#904). */
1817
+ .crisp-select-search { display: flex; align-items: center; gap: var(--crisp-space-2); height: var(--crisp-size-selectTriggerMd); flex-shrink: 0; padding: 0 var(--crisp-space-3-5); border: 1px solid var(--crisp-stroke-select-trigger); border-radius: var(--crisp-radius-md); color: var(--crisp-fg-neutral-muted); }
1781
1818
  .crisp-select-search svg { flex-shrink: 0; }
1782
- .crisp-select-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); color: var(--crisp-fg-select-neutral); }
1819
+ .crisp-select-search input { flex: 1; min-width: 0; border: none; outline: none; background: none; font-family: inherit; font-size: var(--crisp-text-lg); line-height: 19px; color: var(--crisp-fg-select-neutral); }
1783
1820
  .crisp-select-search input::placeholder { color: var(--crisp-fg-select-placeholder); }
1784
1821
  .crisp-select-empty { padding: var(--crisp-space-3) var(--crisp-space-4); text-align: center; font-size: var(--crisp-text-md); color: var(--crisp-fg-neutral-subtle); }
1785
1822
  /* select.yaml's groupLabel -- font-size/line-height/weight are the same
@@ -1834,6 +1871,16 @@
1834
1871
  .crisp-select--width_auto {
1835
1872
  width: auto;
1836
1873
  }
1874
+ .crisp-select--size_small {
1875
+ & .crisp-select-trigger { height: var(--crisp-size-menuRow); border-radius: var(--crisp-radius-md); gap: var(--crisp-space-1-5); padding-inline: var(--crisp-space-2-5); }
1876
+ & .crisp-select-value, & .crisp-select-placeholder { font-size: var(--crisp-text-lg); line-height: 20px; }
1877
+ & .crisp-select-chevron { width: var(--crisp-size-icon); height: var(--crisp-size-icon); }
1878
+ .crisp-select-option { gap: var(--crisp-space-2); }
1879
+ .crisp-select-option-label { font-size: var(--crisp-text-lg); line-height: 19px; }
1880
+ .crisp-select-option-description { font-size: var(--crisp-text-sm); line-height: 16px; }
1881
+ .crisp-select-option-check { width: var(--crisp-space-3); height: var(--crisp-space-3); }
1882
+ .crisp-select-label { padding-top: var(--crisp-space-2); }
1883
+ }
1837
1884
  .crisp-select--size_medium {
1838
1885
  & .crisp-select-trigger { height: var(--crisp-size-selectTriggerMd); border-radius: var(--crisp-radius-md); gap: var(--crisp-space-2); padding-inline: var(--crisp-space-3-5); }
1839
1886
  & .crisp-select-value, & .crisp-select-placeholder { font-size: var(--crisp-text-lg); line-height: 19px; }
@@ -2322,7 +2369,7 @@
2322
2369
  color: var(--crisp-fg-neutral-muted);
2323
2370
  }
2324
2371
  .crisp-text--tone_brand {
2325
- color: var(--crisp-bg-brand-solid);
2372
+ color: var(--crisp-fg-brand-contrast);
2326
2373
  }
2327
2374
  .crisp-text--tone_danger {
2328
2375
  color: var(--crisp-fg-danger);
@@ -2346,8 +2393,9 @@
2346
2393
  &[data-invalid] .crisp-textarea-wrap::after { border-color: var(--crisp-bg-danger); }
2347
2394
  &[data-invalid] .crisp-textarea-wrap:focus-within::after { border-color: var(--crisp-bg-danger); }
2348
2395
  &[data-counted] .crisp-textarea-field { padding-bottom: var(--crisp-space-5); }
2349
- & .crisp-textarea-count { position: absolute; inset-inline-end: 14px; bottom: var(--crisp-space-2-5); font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); pointer-events: none; }
2396
+ & .crisp-textarea-count { position: absolute; inset-inline-end: 14px; bottom: var(--crisp-space-2-5); display: flex; align-items: center; gap: var(--crisp-space-1); font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); pointer-events: none; }
2350
2397
  & .crisp-textarea-count[data-over] { color: var(--crisp-bg-danger); }
2398
+ & .crisp-textarea-progress { flex-shrink: 0; }
2351
2399
  }
2352
2400
 
2353
2401
  @media (prefers-reduced-motion: reduce) {
@@ -2363,11 +2411,11 @@
2363
2411
  &:hover { text-decoration: underline; }
2364
2412
  }
2365
2413
  .crisp-textlink--tone_brand {
2366
- font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-bg-brand-solid);
2414
+ font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-brand-contrast);
2367
2415
  }
2368
2416
  .crisp-textlink--tone_muted {
2369
2417
  font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-regular); color: var(--crisp-fg-muted);
2370
- &:hover { color: var(--crisp-bg-brand-solid); }
2418
+ &:hover { color: var(--crisp-fg-brand-contrast); }
2371
2419
  }
2372
2420
  .crisp-textlink--size_sm {
2373
2421
  font-size: var(--crisp-text-sm);
package/dist/text.css CHANGED
@@ -8,7 +8,7 @@
8
8
  color: var(--crisp-fg-neutral-muted);
9
9
  }
10
10
  .crisp-text--tone_brand {
11
- color: var(--crisp-bg-brand-solid);
11
+ color: var(--crisp-fg-brand-contrast);
12
12
  }
13
13
  .crisp-text--tone_danger {
14
14
  color: var(--crisp-fg-danger);
@@ -9,7 +9,7 @@
9
9
  color: var(--crisp-fg-neutral-muted);
10
10
  }
11
11
  .crisp-text--tone_brand {
12
- color: var(--crisp-bg-brand-solid);
12
+ color: var(--crisp-fg-brand-contrast);
13
13
  }
14
14
  .crisp-text--tone_danger {
15
15
  color: var(--crisp-fg-danger);
package/dist/textarea.css CHANGED
@@ -16,8 +16,9 @@
16
16
  &[data-invalid] .crisp-textarea-wrap::after { border-color: var(--crisp-bg-danger); }
17
17
  &[data-invalid] .crisp-textarea-wrap:focus-within::after { border-color: var(--crisp-bg-danger); }
18
18
  &[data-counted] .crisp-textarea-field { padding-bottom: var(--crisp-space-5); }
19
- & .crisp-textarea-count { position: absolute; inset-inline-end: 14px; bottom: var(--crisp-space-2-5); font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); pointer-events: none; }
19
+ & .crisp-textarea-count { position: absolute; inset-inline-end: 14px; bottom: var(--crisp-space-2-5); display: flex; align-items: center; gap: var(--crisp-space-1); font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); pointer-events: none; }
20
20
  & .crisp-textarea-count[data-over] { color: var(--crisp-bg-danger); }
21
+ & .crisp-textarea-progress { flex-shrink: 0; }
21
22
  }
22
23
 
23
24
  @media (prefers-reduced-motion: reduce) {
@@ -17,8 +17,9 @@
17
17
  &[data-invalid] .crisp-textarea-wrap::after { border-color: var(--crisp-bg-danger); }
18
18
  &[data-invalid] .crisp-textarea-wrap:focus-within::after { border-color: var(--crisp-bg-danger); }
19
19
  &[data-counted] .crisp-textarea-field { padding-bottom: var(--crisp-space-5); }
20
- & .crisp-textarea-count { position: absolute; inset-inline-end: 14px; bottom: var(--crisp-space-2-5); font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); pointer-events: none; }
20
+ & .crisp-textarea-count { position: absolute; inset-inline-end: 14px; bottom: var(--crisp-space-2-5); display: flex; align-items: center; gap: var(--crisp-space-1); font-size: var(--crisp-text-sm); color: var(--crisp-fg-muted); pointer-events: none; }
21
21
  & .crisp-textarea-count[data-over] { color: var(--crisp-bg-danger); }
22
+ & .crisp-textarea-progress { flex-shrink: 0; }
22
23
  }
23
24
 
24
25
  @media (prefers-reduced-motion: reduce) {
package/dist/textlink.css CHANGED
@@ -3,11 +3,11 @@
3
3
  &:hover { text-decoration: underline; }
4
4
  }
5
5
  .crisp-textlink--tone_brand {
6
- font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-bg-brand-solid);
6
+ font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-brand-contrast);
7
7
  }
8
8
  .crisp-textlink--tone_muted {
9
9
  font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-regular); color: var(--crisp-fg-muted);
10
- &:hover { color: var(--crisp-bg-brand-solid); }
10
+ &:hover { color: var(--crisp-fg-brand-contrast); }
11
11
  }
12
12
  .crisp-textlink--size_sm {
13
13
  font-size: var(--crisp-text-sm);
@@ -4,11 +4,11 @@
4
4
  &:hover { text-decoration: underline; }
5
5
  }
6
6
  .crisp-textlink--tone_brand {
7
- font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-bg-brand-solid);
7
+ font-size: var(--crisp-text-sm); font-weight: var(--crisp-weight-medium); color: var(--crisp-fg-brand-contrast);
8
8
  }
9
9
  .crisp-textlink--tone_muted {
10
10
  font-size: var(--crisp-text-md); font-weight: var(--crisp-weight-regular); color: var(--crisp-fg-muted);
11
- &:hover { color: var(--crisp-bg-brand-solid); }
11
+ &:hover { color: var(--crisp-fg-brand-contrast); }
12
12
  }
13
13
  .crisp-textlink--size_sm {
14
14
  font-size: var(--crisp-text-sm);
package/dist/tokens.css CHANGED
@@ -27,14 +27,16 @@
27
27
  font-display: swap;
28
28
  }
29
29
  :root {
30
- --crisp-bg-brand-solid: #266df0;
31
- --crisp-bg-brand-solid-pressed: #1f5fd6;
30
+ --crisp-bg-brand-solid: #0298d9;
31
+ --crisp-bg-brand-solid-pressed: #0283bb;
32
+ --crisp-bg-brand-contrast: #0278ac;
33
+ --crisp-fg-brand-contrast: #0278ac;
32
34
  --crisp-fg-on-brand: #ffffff;
33
35
  --crisp-fg-on-tone: #101112;
34
36
  --crisp-bg-surface: #ffffff;
35
- --crisp-bg-raised: #f4f4f5;
37
+ --crisp-bg-raised: #f7f8f9;
36
38
  --crisp-bg-surface-muted: #f6f7f7;
37
- --crisp-border-default: #e4e4e7;
39
+ --crisp-border-default: #dcdee3;
38
40
  --crisp-border-subtle: #eeeff1;
39
41
  --crisp-border-dropzone: #e6e7ea;
40
42
  --crisp-border-divider: #e6e7ea;
@@ -56,9 +58,9 @@
56
58
  --crisp-shadow-popover3: rgba(24,41,75,0.16);
57
59
  --crisp-fg-primary: #101112;
58
60
  --crisp-fg-muted: #71717a;
59
- --crisp-bg-danger: #e5484d;
60
- --crisp-bg-danger-solid: #ba2525;
61
- --crisp-fg-danger: #eb3b3b;
61
+ --crisp-bg-danger: #fa342c;
62
+ --crisp-bg-danger-solid: #ca1d13;
63
+ --crisp-fg-danger: #fa342c;
62
64
  --crisp-stroke-field-focus: #1a1c20;
63
65
  --crisp-fg-disabled: #d1d3d8;
64
66
  --crisp-bg-neutral-weak: #f3f4f5;
@@ -67,8 +69,9 @@
67
69
  --crisp-fg-neutral-subtle: #868b94;
68
70
  --crisp-fg-neutral-muted: #555d6d;
69
71
  --crisp-stroke-focus-ring: #1e82eb;
70
- --crisp-bg-success: #1f9d57;
71
- --crisp-bg-warning: #b5730f;
72
+ --crisp-bg-success: #079171;
73
+ --crisp-bg-warning: #9b7821;
74
+ --crisp-bg-warning-solid: #fbdc65;
72
75
  --crisp-bg-orange: #f97514;
73
76
  --crisp-bg-cyan: #00b9eb;
74
77
  --crisp-bg-purple: #9b69ff;
@@ -95,8 +98,10 @@
95
98
  }
96
99
 
97
100
  [data-theme="dark"] {
98
- --crisp-bg-brand-solid: #266df0;
99
- --crisp-bg-brand-solid-pressed: #1f5fd6;
101
+ --crisp-bg-brand-solid: #0298d9;
102
+ --crisp-bg-brand-solid-pressed: #0283bb;
103
+ --crisp-bg-brand-contrast: #0278ac;
104
+ --crisp-fg-brand-contrast: #0278ac;
100
105
  --crisp-fg-on-brand: #ffffff;
101
106
  --crisp-fg-on-tone: #101112;
102
107
  --crisp-bg-surface: #0a0a0a;
@@ -137,6 +142,7 @@
137
142
  --crisp-stroke-focus-ring: #5e98fe;
138
143
  --crisp-bg-success: #2ea968;
139
144
  --crisp-bg-warning: #e0982a;
145
+ --crisp-bg-warning-solid: #e0982a;
140
146
  --crisp-bg-orange: #f97514;
141
147
  --crisp-bg-cyan: #00b9eb;
142
148
  --crisp-bg-purple: #9b69ff;
@@ -175,6 +181,7 @@
175
181
  --crisp-space-1-5: 6px;
176
182
  --crisp-space-2-5: 10px;
177
183
  --crisp-space-3-5: 14px;
184
+ --crisp-radius-xs: 4px;
178
185
  --crisp-radius-chip: 7px;
179
186
  --crisp-radius-sm: 6px;
180
187
  --crisp-radius-md: 8px;
package/dist/tokens.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "color": {
3
3
  "light": {
4
- "bgBrandSolid": "#266df0",
5
- "bgBrandSolidPressed": "#1f5fd6",
4
+ "bgBrandSolid": "#0298d9",
5
+ "bgBrandSolidPressed": "#0283bb",
6
+ "bgBrandContrast": "#0278ac",
7
+ "fgBrandContrast": "#0278ac",
6
8
  "fgOnBrand": "#ffffff",
7
9
  "fgOnTone": "#101112",
8
10
  "bgSurface": "#ffffff",
9
- "bgRaised": "#f4f4f5",
11
+ "bgRaised": "#f7f8f9",
10
12
  "bgSurfaceMuted": "#f6f7f7",
11
- "borderDefault": "#e4e4e7",
13
+ "borderDefault": "#dcdee3",
12
14
  "borderSubtle": "#eeeff1",
13
15
  "borderDropzone": "#e6e7ea",
14
16
  "borderDivider": "#e6e7ea",
@@ -30,9 +32,9 @@
30
32
  "shadowPopover3": "rgba(24,41,75,0.16)",
31
33
  "fgPrimary": "#101112",
32
34
  "fgMuted": "#71717a",
33
- "bgDanger": "#e5484d",
34
- "bgDangerSolid": "#ba2525",
35
- "fgDanger": "#eb3b3b",
35
+ "bgDanger": "#fa342c",
36
+ "bgDangerSolid": "#ca1d13",
37
+ "fgDanger": "#fa342c",
36
38
  "strokeFieldFocus": "#1a1c20",
37
39
  "fgDisabled": "#d1d3d8",
38
40
  "bgNeutralWeak": "#f3f4f5",
@@ -41,8 +43,9 @@
41
43
  "fgNeutralSubtle": "#868b94",
42
44
  "fgNeutralMuted": "#555d6d",
43
45
  "strokeFocusRing": "#1e82eb",
44
- "bgSuccess": "#1f9d57",
45
- "bgWarning": "#b5730f",
46
+ "bgSuccess": "#079171",
47
+ "bgWarning": "#9b7821",
48
+ "bgWarningSolid": "#fbdc65",
46
49
  "bgOrange": "#f97514",
47
50
  "bgCyan": "#00b9eb",
48
51
  "bgPurple": "#9b69ff",
@@ -68,8 +71,10 @@
68
71
  "shadowSelect": "#0000001f"
69
72
  },
70
73
  "dark": {
71
- "bgBrandSolid": "#266df0",
72
- "bgBrandSolidPressed": "#1f5fd6",
74
+ "bgBrandSolid": "#0298d9",
75
+ "bgBrandSolidPressed": "#0283bb",
76
+ "bgBrandContrast": "#0278ac",
77
+ "fgBrandContrast": "#0278ac",
73
78
  "fgOnBrand": "#ffffff",
74
79
  "fgOnTone": "#101112",
75
80
  "bgSurface": "#0a0a0a",
@@ -110,6 +115,7 @@
110
115
  "strokeFocusRing": "#5e98fe",
111
116
  "bgSuccess": "#2ea968",
112
117
  "bgWarning": "#e0982a",
118
+ "bgWarningSolid": "#e0982a",
113
119
  "bgOrange": "#f97514",
114
120
  "bgCyan": "#00b9eb",
115
121
  "bgPurple": "#9b69ff",
@@ -140,9 +146,9 @@
140
146
  "gray00": "#ffffff",
141
147
  "white": "#ffffff",
142
148
  "ink": "#101112",
143
- "gray50": "#f4f4f5",
149
+ "gray50": "#f7f8f9",
144
150
  "gray900": "#101112",
145
- "line200": "#e4e4e7",
151
+ "line200": "#dcdee3",
146
152
  "line100": "#eeeff1",
147
153
  "line150": "#e6e7ea",
148
154
  "gray25": "#f6f7f7",
@@ -164,11 +170,12 @@
164
170
  "shadowPopover2": "rgba(28,40,64,0.12)",
165
171
  "shadowPopover3": "rgba(24,41,75,0.16)",
166
172
  "gray400": "#71717a",
167
- "brand600": "#266df0",
168
- "brand700": "#1f5fd6",
169
- "red600": "#e5484d",
170
- "red700": "#ba2525",
171
- "red500": "#eb3b3b",
173
+ "brand600": "#0298d9",
174
+ "brand700": "#0283bb",
175
+ "brandContrast": "#0278ac",
176
+ "red600": "#fa342c",
177
+ "red700": "#ca1d13",
178
+ "red500": "#fa342c",
172
179
  "fieldFocus": "#1a1c20",
173
180
  "disabledFg": "#d1d3d8",
174
181
  "neutralWeak": "#f3f4f5",
@@ -177,8 +184,9 @@
177
184
  "neutralSubtle": "#868b94",
178
185
  "neutralMuted": "#555d6d",
179
186
  "focusRing": "#1e82eb",
180
- "green600": "#1f9d57",
181
- "amber600": "#b5730f",
187
+ "green600": "#079171",
188
+ "amber600": "#9b7821",
189
+ "amberSolid": "#fbdc65",
182
190
  "orange600": "#f97514",
183
191
  "cyan600": "#00b9eb",
184
192
  "purple600": "#9b69ff",
@@ -228,8 +236,9 @@
228
236
  "shadowPopover2": "rgba(0,0,0,0.24)",
229
237
  "shadowPopover3": "rgba(0,0,0,0.32)",
230
238
  "gray400": "#9a9aa2",
231
- "brand600": "#266df0",
232
- "brand700": "#1f5fd6",
239
+ "brand600": "#0298d9",
240
+ "brand700": "#0283bb",
241
+ "brandContrast": "#0278ac",
233
242
  "red600": "#ff5a5f",
234
243
  "red700": "#ba2525",
235
244
  "red500": "#ff5a5f",
@@ -243,6 +252,7 @@
243
252
  "focusRing": "#5e98fe",
244
253
  "green600": "#2ea968",
245
254
  "amber600": "#e0982a",
255
+ "amberSolid": "#e0982a",
246
256
  "orange600": "#f97514",
247
257
  "cyan600": "#00b9eb",
248
258
  "purple600": "#9b69ff",
@@ -280,6 +290,7 @@
280
290
  "3.5": 14
281
291
  },
282
292
  "radius": {
293
+ "xs": 4,
283
294
  "chip": 7,
284
295
  "sm": 6,
285
296
  "md": 8,
@@ -0,0 +1,23 @@
1
+ import * as React from "react";
2
+ export type AccentPickerProps = Omit<React.ComponentPropsWithoutRef<"div">, "value" | "className"> & {
3
+ /** Hex (or any CSS) colours, in display order. */
4
+ colors: string[];
5
+ /** Controlled selected colour. Omit to let the picker manage it (see `defaultValue`). */
6
+ value?: string;
7
+ /** Initially selected colour, when uncontrolled. */
8
+ defaultValue?: string;
9
+ onValueChange?: (color: string) => void;
10
+ className?: string;
11
+ };
12
+ /**
13
+ * A row of selectable colour swatches — Attio's own accent-colour picker
14
+ * (Settings > Appearance). Not a fixed palette: pass the colours (and the
15
+ * accent isn't crisp's concern to theme the app with — this only picks one).
16
+ * Same roving-focus/arrow-key model every other crisp radio-like control
17
+ * shares (`useRadioGroupKeyboard`, also used by `RadioGroup` and
18
+ * `Segmented`).
19
+ */
20
+ export declare function AccentPicker({ colors, value, defaultValue, onValueChange, className, onKeyDown: onKeyDownProp, ...rest }: AccentPickerProps): React.JSX.Element;
21
+ export declare namespace AccentPicker {
22
+ var displayName: string;
23
+ }
@@ -0,0 +1,3 @@
1
+ declare const config: import("../..").RecipeConfig<import("../..").RecipeVariantRecord>;
2
+ export declare const accentpickerRecipe: import("../..").RecipeFn<import("../..").RecipeVariantRecord>;
3
+ export default config;
@@ -0,0 +1,2 @@
1
+ export { AccentPicker, type AccentPickerProps } from "./accentpicker";
2
+ export { accentpickerRecipe } from "./accentpicker.recipe";
@@ -32,12 +32,12 @@ declare const spec: {
32
32
  readonly parts: [{
33
33
  readonly selector: "&:hover";
34
34
  readonly decls: {
35
- background: `var(--${string})`;
35
+ readonly filter: "brightness(0.96)";
36
36
  };
37
37
  }, {
38
38
  readonly selector: "&:active";
39
39
  readonly decls: {
40
- background: `var(--${string})`;
40
+ readonly filter: "brightness(0.92)";
41
41
  };
42
42
  }];
43
43
  };
@@ -4,6 +4,12 @@ import { inputRecipe } from "./input.recipe";
4
4
  export type InputProps = Omit<React.ComponentPropsWithoutRef<"input">, "size"> & VariantProps<typeof inputRecipe> & {
5
5
  /** Class for the wrapper that draws the field chrome and focus ring. */
6
6
  className?: string;
7
+ /**
8
+ * Content after the value (crisp#634) — e.g. an "Edit" button on a
9
+ * read-only field. Measured live on Attio's own Settings > Profile
10
+ * primary-email field.
11
+ */
12
+ suffix?: React.ReactNode;
7
13
  };
8
14
  export declare const Input: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref">, "size"> & VariantProps<import("../..").RecipeFn<{
9
15
  size: {
@@ -30,4 +36,10 @@ export declare const Input: React.ForwardRefExoticComponent<Omit<Omit<React.Deta
30
36
  }> & {
31
37
  /** Class for the wrapper that draws the field chrome and focus ring. */
32
38
  className?: string;
39
+ /**
40
+ * Content after the value (crisp#634) — e.g. an "Edit" button on a
41
+ * read-only field. Measured live on Attio's own Settings > Profile
42
+ * primary-email field.
43
+ */
44
+ suffix?: React.ReactNode;
33
45
  } & React.RefAttributes<HTMLInputElement>>;
@@ -53,10 +53,11 @@ export type MultiSelectProps = Omit<React.ComponentPropsWithoutRef<"div">, "valu
53
53
  /** 2px red border + `aria-invalid`, matching `Input`'s and `Select`'s. */
54
54
  invalid?: boolean;
55
55
  /**
56
- * seed-design's two Select-family sizes (crisp/#882): `medium` (default,
57
- * 40px trigger floor) or `large` (52px). Purely visual.
56
+ * `small` (default, crisp/#889) is Attio's own 32px trigger floor — lines
57
+ * up with `Input`'s own size. `medium`/`large` are seed-design's own
58
+ * 40px/52px floors (crisp/#882), opt-in. Purely visual.
58
59
  */
59
- size?: "medium" | "large";
60
+ size?: "small" | "medium" | "large";
60
61
  /**
61
62
  * `ghost` fills whatever row it's embedded in instead of the fixed
62
63
  * trigger height — for inline table cell editors (crisp/#882, matching
@@ -1,5 +1,6 @@
1
1
  declare const config: import("../..").RecipeConfig<{
2
2
  size: {
3
+ small: string;
3
4
  medium: string;
4
5
  large: string;
5
6
  };
@@ -14,6 +15,7 @@ declare const config: import("../..").RecipeConfig<{
14
15
  }>;
15
16
  export declare const multiselectRecipe: import("../..").RecipeFn<{
16
17
  size: {
18
+ small: string;
17
19
  medium: string;
18
20
  large: string;
19
21
  };
@@ -28,6 +30,7 @@ export declare const multiselectRecipe: import("../..").RecipeFn<{
28
30
  }> & {
29
31
  config: import("../..").RecipeConfig<{
30
32
  size: {
33
+ small: string;
31
34
  medium: string;
32
35
  large: string;
33
36
  };