@deriv-ds/design-intelligence-layer 0.6.1 → 0.6.2
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/.claude/skills/build/SKILL.md +74 -14
- package/.claude/skills/build/references/components-and-tokens.md +49 -22
- package/AGENTS.md +3 -3
- package/CHANGELOG.md +7 -0
- package/README.md +21 -15
- package/dist/index.cjs +1473 -1181
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +42 -6
- package/dist/index.d.ts +42 -6
- package/dist/index.js +1491 -1209
- package/dist/index.js.map +1 -1
- package/guides/design-system-guide/deriv-design-intelligence-guide.md +214 -176
- package/guides/design-system-guide/icon-reference.md +1 -1
- package/guides/design-system-guide/quill-ds-guide.md +31 -30
- package/guides/rules/design-system-consuming-project.mdc +42 -30
- package/package.json +1 -1
- package/src/styles.css +73 -3
|
@@ -14,7 +14,7 @@ import { Icon } from "@deriv-ds/design-intelligence-layer";
|
|
|
14
14
|
<Icon name="bell" />
|
|
15
15
|
|
|
16
16
|
// Explicit weight + styling via className
|
|
17
|
-
<Icon name="circle-check" weight="fill" className="size-4 text-success" />
|
|
17
|
+
<Icon name="circle-check" weight="fill" className="size-4 text-[var(--text-success-default)]" />
|
|
18
18
|
<Icon name="user" weight="regular" className="text-subtle" />
|
|
19
19
|
```
|
|
20
20
|
|
|
@@ -39,7 +39,8 @@ ALWAYS use semantic tokens:
|
|
|
39
39
|
✅ text-prominent, text-subtle, text-on-prominent-static-inverse
|
|
40
40
|
✅ border-default, border-selected, ring-ring
|
|
41
41
|
✅ bg-primary, bg-primary-hover, bg-secondary-hover
|
|
42
|
-
✅ text-warning, text-info, text-alert-info-text, text-alert-error-text
|
|
42
|
+
✅ text-warning, text-info, text-success, text-error (the four status text utilities), text-alert-info-text, text-alert-error-text
|
|
43
|
+
✅ text-on-primary / text-on-success / text-on-error / text-on-warning / text-on-info (foreground on a solid coloured surface)
|
|
43
44
|
✅ Opacity on a token IS allowed: bg-primary/20, border-default/50, ring-primary/10
|
|
44
45
|
```
|
|
45
46
|
|
|
@@ -59,7 +60,7 @@ Token rules apply ONLY to:
|
|
|
59
60
|
### Rule 4 — Do NOT install or import these separately
|
|
60
61
|
|
|
61
62
|
```
|
|
62
|
-
❌ lucide-react or any icon library — icons come from
|
|
63
|
+
❌ lucide-react or any icon library — icons come from `@deriv/quill-icons` via the package's <Icon /> component (see icon-reference.md in this folder)
|
|
63
64
|
❌ tailwindcss — the package ships its own Tailwind v4 config
|
|
64
65
|
❌ @apply with hsl(var(--token)) — Tailwind v4 uses CSS variables directly
|
|
65
66
|
❌ tailwind.config.js — configuration is handled by the package via CSS
|
|
@@ -135,14 +136,14 @@ import { Button, Card, Tag } from "@deriv-ds/design-intelligence-layer"
|
|
|
135
136
|
|
|
136
137
|
### 2.3 — Semantic (Status)
|
|
137
138
|
|
|
138
|
-
| CSS Variable | Tailwind Class
|
|
139
|
-
| --------------------------- |
|
|
140
|
-
| `--text-
|
|
141
|
-
| `--text-
|
|
142
|
-
| `--text-
|
|
143
|
-
| `--text-
|
|
139
|
+
| CSS Variable | Tailwind Class | Usage |
|
|
140
|
+
| --------------------------- | ------------------------------------ | ------------------------- |
|
|
141
|
+
| `--text-warning-default` | `text-warning` | Warning / Caution / Non-destructive alerts (yellow-900 light, yellow-500 dark) |
|
|
142
|
+
| `--text-information-default`| `text-info` | Informational alerts (blue-900 light, blue-500 dark) |
|
|
143
|
+
| `--text-success-default` | `text-success` | Success / Positive outcomes (green-900 light, green-500 dark) |
|
|
144
|
+
| `--text-error-default` | `text-error` | Error / Negative outcomes (red-900 light, red-500 dark) |
|
|
144
145
|
|
|
145
|
-
> All
|
|
146
|
+
> **All four status colours are bare utility classes:** `text-warning`, `text-info`, `text-success`, `text-error` (each mapped to its `--text-*-default` value in the theme bridge — theme-aware and opacity-friendly, e.g. `bg-success/10`). The older `text-[var(--text-success-default)]` / `text-[var(--text-error-default)]` form still resolves (the package's own blocks such as `hero-mobile-transaction.tsx` use it) but new code should prefer the utilities. Foundation background tokens are also available: `--background-success-default`, `--background-error-default`, `--background-warning-default`, `--background-information-default`. For text/icons on a **solid** coloured surface use `text-on-primary` / `text-on-success` / `text-on-error` / `text-on-warning` / `text-on-info`. For a **solid opaque status tint** that won't bleed on a coloured background use `bg-success-surface` / `bg-error-surface` / `bg-warning-surface` / `bg-info-surface` (built with `color-mix`, theme-aware). For structured alpha surfaces, use the primitive alpha scales — see Section 2.10.
|
|
146
147
|
|
|
147
148
|
### 2.4 — Text & Icon Colors
|
|
148
149
|
|
|
@@ -160,7 +161,7 @@ import { Button, Card, Tag } from "@deriv-ds/design-intelligence-layer"
|
|
|
160
161
|
| `--border-subtle-default` | (via `--input`) | Subtle / light border (slate @ 8% alpha) |
|
|
161
162
|
| `--border-selected-default` | `border-selected` | Selected / emphasized border (solid slate-1200) |
|
|
162
163
|
| `--input` | `border-input` | Input resting state border (aliases `--border-subtle-default`) |
|
|
163
|
-
| `--ring` | `ring-ring`
|
|
164
|
+
| `--ring` | `ring-ring` | Focus ring color (blue-800 `#1789E1` — chosen to clear WCAG 1.4.11's 3:1 minimum on both light and dark surfaces; see issue #38). Pair with `ring-2 ring-offset-2 ring-offset-primary-surface`, not `border-ring` |
|
|
164
165
|
|
|
165
166
|
### 2.6 — Supporting Colors
|
|
166
167
|
|
|
@@ -182,7 +183,7 @@ import { Button, Card, Tag } from "@deriv-ds/design-intelligence-layer"
|
|
|
182
183
|
| Subtle hover tint | `bg-primary/[0.08]` |
|
|
183
184
|
| Medium highlight | `bg-primary/[0.16]` |
|
|
184
185
|
| Selected/active tint | `bg-primary/10` |
|
|
185
|
-
| Status tint backgrounds | `bg-
|
|
186
|
+
| Status tint backgrounds | `bg-warning/10`, `bg-info/10`, `bg-success/10`, `bg-error/10` (all utilities); or the foundation tints `bg-[var(--background-success-default)]` / `bg-[var(--background-error-default)]` |
|
|
186
187
|
|
|
187
188
|
### 2.8 — Interactive States
|
|
188
189
|
|
|
@@ -225,6 +226,8 @@ import { Button, Card, Tag } from "@deriv-ds/design-intelligence-layer"
|
|
|
225
226
|
<div className="transition-colors duration-fast ease-standard">...</div>
|
|
226
227
|
```
|
|
227
228
|
|
|
229
|
+
**Reduced motion:** the base layer includes a global `@media (prefers-reduced-motion: reduce)` rule that collapses all `animation-duration` / `transition-duration` to `0.01ms` and forces `scroll-behavior: auto` for every element. This is automatic — components using the duration/easing tokens above don't need to add anything extra. If you hand-roll a custom animation outside these tokens (e.g. a raw `@keyframes` or a JS-driven animation library), you must independently respect `prefers-reduced-motion` since the CSS rule only overrides CSS-driven animations/transitions.
|
|
230
|
+
|
|
228
231
|
### 2.10 — Primitive Alpha Scales
|
|
229
232
|
|
|
230
233
|
> Raw alpha (opacity) variants. These are **internal CSS variables only** — not exposed as Tailwind utility classes. Reference them only from semantic or component tokens, never directly in components.
|
|
@@ -274,7 +277,7 @@ import { Button, Card, Tag } from "@deriv-ds/design-intelligence-layer"
|
|
|
274
277
|
| `--primitive-emerald-alpha-*`| `oklch(0.725 0.150 166.0)` | Real-account highlights |
|
|
275
278
|
| `--primitive-cherry-alpha-*`| `oklch(0.571 0.229 18.2)` | Reserved |
|
|
276
279
|
|
|
277
|
-
> The `--overlay` semantic token resolves to
|
|
280
|
+
> The `--overlay` semantic token resolves to black at 50% opacity (via the `--overlay` CSS variable). Use `bg-overlay` for modal/dialog/sheet/drawer backdrops — do not manually reconstruct it with `bg-black/50`. The alpha-stop number in the primitive scale naming convention (e.g. `alpha-50`) refers to the palette stop index, not the opacity percentage; the actual opacity is defined separately in the semantic token.
|
|
278
281
|
|
|
279
282
|
---
|
|
280
283
|
|
|
@@ -285,8 +288,8 @@ import { Button, Card, Tag } from "@deriv-ds/design-intelligence-layer"
|
|
|
285
288
|
| IF you need to... | THEN use | NEVER use |
|
|
286
289
|
| -------------------------------------- | --------------------------------- | -------------------------------------- |
|
|
287
290
|
| Pick a primary CTA button color | `bg-primary` | Green, blue, or any other color for primary CTA |
|
|
288
|
-
| Show SUCCESS / profit / positive | `text-success`
|
|
289
|
-
| Show ERROR / negative | `text-error`
|
|
291
|
+
| Show SUCCESS / profit / positive | `text-success` | Primary coral for success, non-token green |
|
|
292
|
+
| Show ERROR / negative | `text-error` | Primary coral for error, non-token red |
|
|
290
293
|
| Show WARNING / caution | `text-warning` | Raw orange hex or primary tint |
|
|
291
294
|
| Color a tab container background | `bg-tabs` | `bg-secondary-surface` for tabs |
|
|
292
295
|
| Color an active/selected tab | `bg-tabs-active` | `bg-primary-surface` for active tab |
|
|
@@ -301,10 +304,11 @@ import { Button, Card, Tag } from "@deriv-ds/design-intelligence-layer"
|
|
|
301
304
|
| Add a default border | `border-default` | Solid black borders, raw hex |
|
|
302
305
|
| Add a selected/strong border | `border-selected` | — |
|
|
303
306
|
| Style an input (resting) | `border-input` | Solid colored backgrounds |
|
|
304
|
-
| Style an
|
|
307
|
+
| Style an interactive element (focused) | `ring-2 ring-ring ring-offset-2 ring-offset-primary-surface` | `ring-ring/50` (fails 3:1 contrast), generic shadows |
|
|
308
|
+
| Style an input (focused) | Border-based: `border-field-*-border-focus` (see Section 8.5 Input) | `ring-ring` on inputs — inputs use border, not ring, focus indication |
|
|
305
309
|
| Pick a heading font | `font-display` | System fonts, raw font-family names |
|
|
306
310
|
| Pick a body font | `font-body` | Raw font-family names |
|
|
307
|
-
| Style button text | `font-display font-
|
|
311
|
+
| Style button text | `font-display font-extrabold`, sentence case | `uppercase` on buttons, `font-bold` |
|
|
308
312
|
| Write white text on a dark surface | `text-on-prominent-static-inverse`| `text-white` or raw white hex |
|
|
309
313
|
|
|
310
314
|
---
|
|
@@ -368,7 +372,7 @@ These sizes differ from standard Tailwind defaults — use the design system val
|
|
|
368
372
|
| Context | Class | Weight |
|
|
369
373
|
| ------------------------ | -------------- | ------------------- |
|
|
370
374
|
| Page headings | `font-display` | `font-extrabold` (800) |
|
|
371
|
-
| Button labels | `font-display` | `font-
|
|
375
|
+
| Button labels | `font-display` | `font-extrabold` (800), sentence case |
|
|
372
376
|
| Body text | `font-body` | `font-normal` (400) |
|
|
373
377
|
| Tiny labels / decorative | `font-body` | `font-medium` (500) |
|
|
374
378
|
|
|
@@ -434,13 +438,13 @@ The design system uses a custom radius scale (base = 10px). Use these named toke
|
|
|
434
438
|
|
|
435
439
|
### 6.3 — Button Typography & States
|
|
436
440
|
|
|
437
|
-
All buttons: `font-display font-
|
|
441
|
+
All buttons: `font-display font-extrabold` (800), sentence case (no `uppercase`, no `tracking-wide`).
|
|
438
442
|
|
|
439
443
|
| State | Behavior |
|
|
440
444
|
| -------- | ------------------------------------------------ |
|
|
441
445
|
| Default | Base styling per variant |
|
|
442
446
|
| Hover | Color shift per variant (see above) |
|
|
443
|
-
| Focus |
|
|
447
|
+
| Focus | 2px `ring-ring` (full opacity, blue-800) + 2px `ring-offset-primary-surface` — clears WCAG 1.4.11 3:1 |
|
|
444
448
|
| Pressed | Pressed bg token per variant (e.g. `bg-button-primary-bg-pressed`) |
|
|
445
449
|
| Loading | `opacity-24`, `pointer-events-none`, `data-loading`, `aria-busy` — applies to all variants |
|
|
446
450
|
| Disabled | Dedicated disabled tokens: `bg-button-disabled-normal-bg`, `text-button-disabled-normal-text` — not generic opacity |
|
|
@@ -544,8 +548,6 @@ import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, Dialog
|
|
|
544
548
|
| Kbd | [simple] | KbdGroup |
|
|
545
549
|
| Label | [simple] | — |
|
|
546
550
|
| Link | [simple] | — |
|
|
547
|
-
| Menubar | [complex] | MenubarMenu, MenubarTrigger, MenubarContent, MenubarItem, MenubarSeparator, MenubarLabel, MenubarCheckboxItem, MenubarRadioGroup, MenubarRadioItem, MenubarSub, MenubarSubTrigger, MenubarSubContent, MenubarShortcut |
|
|
548
|
-
| Modal | [complex] | ModalTrigger, ModalContent, ModalHeader, ModalFooter, ModalTitle, ModalDescription, ModalAction, ModalCancel, ModalMedia |
|
|
549
551
|
| NativeSelect | [simple] | NativeSelectOption, NativeSelectOptGroup |
|
|
550
552
|
| NavigationMenu | [complex] | NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger, NavigationMenuContent, NavigationMenuLink, NavigationMenuIndicator, NavigationMenuViewport, navigationMenuTriggerStyle |
|
|
551
553
|
| OTPField | [composed] | OTPFieldGroup, OTPFieldSlot, OTPFieldSeparator |
|
|
@@ -562,7 +564,7 @@ import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, Dialog
|
|
|
562
564
|
| Sidebar | [complex] | SidebarProvider, SidebarTrigger, SidebarInset, SidebarHeader, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarGroupContent, SidebarMenu, SidebarMenuItem, SidebarMenuButton, SidebarRail, useSidebar |
|
|
563
565
|
| Skeleton | [simple] | — |
|
|
564
566
|
| Slider | [simple] | — |
|
|
565
|
-
| Sonner (Toaster) | [simple] | — (
|
|
567
|
+
| Sonner (Toaster) | [simple] | — (the imperative `toast` is re-exported from the package: `import { Snackbar, toast } from "@deriv-ds/design-intelligence-layer"`) |
|
|
566
568
|
| Spinner | [simple] | — |
|
|
567
569
|
| Stepper | [simple] | — |
|
|
568
570
|
| Switch | [simple] | — |
|
|
@@ -581,9 +583,9 @@ These are styling behaviors you can't discover from TypeScript types alone:
|
|
|
581
583
|
|
|
582
584
|
| Component | Note |
|
|
583
585
|
|-----------|------|
|
|
584
|
-
| Button | `font-display font-
|
|
586
|
+
| Button | `font-display font-extrabold` (800), sentence case (no `uppercase`). Primary: `text-on-prominent-static-inverse`. Radius: `rounded-full` (pill). 4 variants: primary, secondary, tertiary, ghost |
|
|
585
587
|
| Card | Flat by default (no shadow). Add elevation manually: `className="shadow-sm"` or use elevation tokens `var(--elevation-100)` through `var(--elevation-500)` |
|
|
586
|
-
| Input | Resting: `border-input`. Focus: `border-
|
|
588
|
+
| Input | Resting: `border-input`. Focus: border-based (`border-field-*-border-focus` + border-width step-up), no ring. Radius: `rounded-sm` (6px). **Variants:** `outline` (default), `fill`, `inverse` (sunken translucent fill + light foregrounds — for inputs ON a brand/coloured surface; also on `InputGroup`). **`readOnly`** renders a distinct borderless, softly-filled "display only" state (separate from the faded `disabled` state). |
|
|
587
589
|
| Tooltip | Bubble: uses component tokens `--tooltip-bg-default` + `--tooltip-text-default`. Always wrap in `<TooltipProvider>` |
|
|
588
590
|
| Sidebar | Menu buttons use `rounded-sm`. Selection: `bg-secondary-hover` + `text-primary` + `font-semibold` |
|
|
589
591
|
| Breadcrumb | Active page: `text-primary font-medium`. Links: `text-subtle` |
|
|
@@ -595,7 +597,6 @@ These are styling behaviors you can't discover from TypeScript types alone:
|
|
|
595
597
|
| Switch | Checked track: `bg-slider-range`. Checked thumb: `bg-primary` |
|
|
596
598
|
| Slider | Thumb: square `rounded-[4px]`, `bg-primary`. Track range: `bg-slider-range` |
|
|
597
599
|
| Dialog/Sheet | Footer buttons should use `size="md"`. Overlay: `bg-overlay` |
|
|
598
|
-
| Menubar | Hover: `bg-primary/[0.08]`. Open state: `bg-primary/10` |
|
|
599
600
|
| Toggle | Pressed: `bg-primary/10` + `border-primary` + `text-primary` |
|
|
600
601
|
| Calendar | Selected: `bg-secondary-hover` + `text-primary font-bold`. Today: primary dot below date |
|
|
601
602
|
|
|
@@ -634,9 +635,9 @@ Landing page hero sections in multiple layout types.
|
|
|
634
635
|
| Type 1 — Mobile | Single column stacked: text content centred above, image panel full-width below |
|
|
635
636
|
| Type 2 — Desktop | Centred single-column: tagline pill + heading + body + single primary CTA with `<Icon name="arrow-right" />`; no image |
|
|
636
637
|
|
|
637
|
-
**Components used:** `Button` (default `sm`, `secondary sm`); `<Icon name="arrow-up-right" />`, `<Icon name="arrow-right" />` (
|
|
638
|
+
**Components used:** `Button` (default `sm`, `secondary sm`); `<Icon name="arrow-up-right" />`, `<Icon name="arrow-right" />` (`@deriv/quill-icons` via the `Icon` component)
|
|
638
639
|
|
|
639
|
-
**Tokens used:** `bg-primary-surface`, `bg-secondary-surface`, `border-default`, `text-prominent`, `text-subtle`, `bg-success`, `rounded-xl`, `rounded-full`, `px-layout-margin-inline`, `gap-layout-gutter`, `py-24`, `text-5xl`, `font-semibold`, `font-display`, `tracking-tight`, `text-lg`, `font-body`, `text-sm`, `shadow-sm`, `max-w-2xl`
|
|
640
|
+
**Tokens used:** `bg-primary-surface`, `bg-secondary-surface`, `border-default`, `text-prominent`, `text-subtle`, `bg-[var(--background-success-default)]`, `rounded-xl`, `rounded-full`, `px-layout-margin-inline`, `gap-layout-gutter`, `py-24`, `text-5xl`, `font-semibold`, `font-display`, `tracking-tight`, `text-lg`, `font-body`, `text-sm`, `shadow-sm`, `max-w-2xl`
|
|
640
641
|
|
|
641
642
|
---
|
|
642
643
|
|
|
@@ -652,18 +653,18 @@ Landing page hero sections in multiple layout types.
|
|
|
652
653
|
| Using `text-on-decorative` | Use `text-subtle` |
|
|
653
654
|
| Using `font-mono` expecting Inter | Use `font-display` or `font-body` |
|
|
654
655
|
| Using `font-semibold` for headings | Use `font-extrabold` (800) for headings |
|
|
655
|
-
| Using `font-bold` for buttons | Use `font-
|
|
656
|
+
| Using `font-bold` or `font-semibold` for buttons | Use `font-extrabold` (800) for buttons |
|
|
656
657
|
| Using `uppercase` on buttons | Buttons use sentence case (no `uppercase`) |
|
|
657
658
|
| Using standard TW sizes for headings (e.g. `text-6xl` = 60px) | Use design system values (`text-6xl` = 64px in this system) |
|
|
658
659
|
| Using `rounded-[4px]` or `rounded-[2px]` | Use `rounded-xs` (4px) or `rounded-2xs` (2px) |
|
|
659
660
|
| Using small radius on buttons | Buttons use `rounded-full` (pill shape, 999px) |
|
|
660
|
-
| Installing or importing `lucide-react` | Use `<Icon name="..." weight="..." />` (
|
|
661
|
+
| Installing or importing `lucide-react` | Use `<Icon name="..." weight="..." />` (`@deriv/quill-icons`) — catalog in `icon-reference.md` |
|
|
661
662
|
| Adding `tailwind.config.js` | Tailwind v4 uses CSS config via the package |
|
|
662
663
|
| Using `bg-gray-*`, `text-zinc-*`, etc. | Use semantic tokens only |
|
|
663
664
|
| Using `bg-prominent`, `bg-card`, `bg-popover`, `bg-subtle` | Use `bg-primary-surface`, `bg-primary-canvas`, `bg-secondary-surface`, `bg-secondary-canvas` |
|
|
664
665
|
| Using `text-on-prominent`, `text-on-subtle` | Use `text-prominent`, `text-subtle` |
|
|
665
666
|
| Using `border-border-subtle`, `border-border-prominent` | Use `border-default`, `border-selected` |
|
|
666
|
-
| Using `text-semantic-win`, `text-semantic-loss` | Use
|
|
667
|
+
| Using `text-semantic-win`, `text-semantic-loss` | Use the status utilities `text-success` / `text-error` (or `text-warning` / `text-info`) |
|
|
667
668
|
|
|
668
669
|
---
|
|
669
670
|
|
|
@@ -12,7 +12,13 @@ alwaysApply: true
|
|
|
12
12
|
|
|
13
13
|
### Available components (check this list first)
|
|
14
14
|
|
|
15
|
-
Accordion,
|
|
15
|
+
Accordion, AlertDialog, Avatar, AvatarGroup, Badge, Breadcrumb, Button, Calendar, Card, Carousel, Chart, Checkbox, Collapsible, Combobox, Command, ContextMenu, Dialog, Drawer, DropdownMenu, Empty, Field, Form, HoverCard, Input, InputGroup, InputOTP, Item, Kbd, Label, Link, NativeSelect, NavigationMenu, NotificationBanner, Pagination, Popover, Progress, RadioGroup, Resizable, ScrollArea, SectionMessage, Select, Separator, Sheet, Sidebar, Skeleton, Slider, Sonner (Toaster), Spinner, Stepper, Switch, Table, Tabs, Tag, Textarea, Toggle, ToggleGroup, Tooltip
|
|
16
|
+
|
|
17
|
+
> **No `Alert` / `Banner` component.** For an inline status/alert message use `SectionMessage`. For a dismissible banner bar use `NotificationBanner`. Never invent an `Alert` or `Banner` import.
|
|
18
|
+
|
|
19
|
+
### Complexity — ask before building with `[complex]` components
|
|
20
|
+
|
|
21
|
+
Each component in the design guide (Section 8) is tagged `[simple]` (drop-in, one import), `[composed]` (has required sub-components — use the full pattern), or `[complex]` (significant state/setup). Before building with a `[complex]` component, **ask the user clarifying questions first** rather than guessing at configuration. The `[complex]` set is: Calendar, Carousel, Chart, Combobox, Command, Dialog, Drawer, Field, Form, NavigationMenu, Resizable, Sheet, Sidebar.
|
|
16
22
|
|
|
17
23
|
### Decision flow
|
|
18
24
|
|
|
@@ -41,10 +47,10 @@ import { Button, Card, Badge } from "@deriv-ds/design-intelligence-layer"
|
|
|
41
47
|
### Never use
|
|
42
48
|
|
|
43
49
|
```
|
|
44
|
-
❌ Hardcoded hex: #
|
|
50
|
+
❌ Hardcoded hex: #FF444F, #000000, rgba(0,0,0,0.5)
|
|
45
51
|
❌ Raw Tailwind palette: bg-gray-100, text-zinc-500, text-slate-400, bg-black, bg-white
|
|
46
|
-
❌ Arbitrary color: bg-[#EEEEEE], text-[rgba(
|
|
47
|
-
❌ Raw CSS var: bg-[var(--border-subtle)] ← NEVER do this
|
|
52
|
+
❌ Arbitrary color: bg-[#EEEEEE], text-[rgba(255,68,79,0.1)]
|
|
53
|
+
❌ Raw CSS var: bg-[var(--border-subtle)] ← NEVER do this (exception: the success/error status vars below)
|
|
48
54
|
❌ hsl(var()) syntax: hsl(var(--primary)) ← this is Tailwind v3, not v4
|
|
49
55
|
❌ Raw opacity on non-tokens: bg-black/50
|
|
50
56
|
```
|
|
@@ -53,41 +59,45 @@ import { Button, Card, Badge } from "@deriv-ds/design-intelligence-layer"
|
|
|
53
59
|
|
|
54
60
|
#### Background tokens
|
|
55
61
|
```
|
|
56
|
-
✅ bg-
|
|
57
|
-
✅ bg-
|
|
58
|
-
✅ bg-popover
|
|
59
|
-
✅ bg-
|
|
62
|
+
✅ bg-primary-canvas — main page / canvas background
|
|
63
|
+
✅ bg-primary-surface — card/panel/modal surface
|
|
64
|
+
✅ bg-card / bg-popover — alias bg-primary-surface (cards, dropdowns)
|
|
65
|
+
✅ bg-secondary-surface — subtle / muted surface
|
|
66
|
+
✅ bg-secondary-canvas — secondary canvas area
|
|
60
67
|
✅ bg-overlay — modal/dialog backdrop (black 50%) — ONLY for overlays
|
|
61
|
-
✅ bg-primary — brand
|
|
62
|
-
✅ bg-primary-hover — darker
|
|
63
|
-
✅ bg-secondary-hover — light grey
|
|
64
|
-
✅ bg-
|
|
65
|
-
✅ bg-loss — red — loss/negative
|
|
68
|
+
✅ bg-primary — brand coral #FF444F — CTAs and primary actions
|
|
69
|
+
✅ bg-primary-hover — darker coral #E12E3A — primary button hover
|
|
70
|
+
✅ bg-secondary-hover — light grey — outline/secondary button hover
|
|
71
|
+
✅ bg-tabs / bg-tabs-active — tab container / active tab background
|
|
66
72
|
```
|
|
73
|
+
> Do NOT use `bg-prominent` or `bg-subtle` as backgrounds — those classes map to TEXT foreground values.
|
|
67
74
|
|
|
68
75
|
#### Text tokens
|
|
69
76
|
```
|
|
70
|
-
✅ text-
|
|
77
|
+
✅ text-prominent — primary text (headings, body)
|
|
71
78
|
✅ text-on-prominent-static-inverse — always white — for text on dark/primary bg
|
|
72
|
-
✅ text-
|
|
79
|
+
✅ text-subtle — secondary text (descriptions, labels)
|
|
73
80
|
|
|
74
|
-
✅ text-primary — brand
|
|
75
|
-
✅ text-
|
|
76
|
-
✅ text-
|
|
81
|
+
✅ text-primary — brand coral #FF444F
|
|
82
|
+
✅ text-warning / text-info / text-success / text-error — the four status text utilities (theme-aware, opacity-friendly: bg-success/10)
|
|
83
|
+
✅ text-on-primary / text-on-success / text-on-error / text-on-warning / text-on-info — foreground on a SOLID coloured surface
|
|
77
84
|
```
|
|
85
|
+
> All four status text utilities exist (`text-warning`, `text-info`, `text-success`, `text-error`). The older `text-[var(--text-success-default)]` / `text-[var(--text-error-default)]` form still resolves (the package's own blocks use it) but prefer the bare utilities in new code.
|
|
86
|
+
> Use `text-on-*` foregrounds ONLY on the solid brand/status colour (`bg-primary`, `bg-success`, …). On a status *tint* (`bg-success/10`) use `text-success` / `text-error` instead.
|
|
87
|
+
> `text-on-prominent` still resolves but is ALWAYS-WHITE (for dark surfaces), not page body text — use `text-prominent`.
|
|
78
88
|
|
|
79
89
|
#### Border tokens
|
|
80
90
|
```
|
|
81
|
-
✅ border-
|
|
82
|
-
✅ border-
|
|
83
|
-
✅ border-
|
|
84
|
-
✅
|
|
85
|
-
✅ ring-ring — focus ring (blue #2323FF)
|
|
91
|
+
✅ border-default — default UI borders, dividers, cards (slate @ 16% alpha)
|
|
92
|
+
✅ border-selected — selected / emphasized / outline components (solid slate-1200)
|
|
93
|
+
✅ border-input — input field borders
|
|
94
|
+
✅ ring-ring — focus ring (blue #1789E1 — WCAG 3:1 on light + dark; pair with ring-2 + ring-offset-2 ring-offset-primary-surface)
|
|
86
95
|
```
|
|
96
|
+
> `border-border-subtle` / `border-border-prominent` / `border-border` still resolve (deprecated aliases) — prefer `border-default` / `border-selected` in new code.
|
|
87
97
|
|
|
88
98
|
#### Opacity on a token is fine
|
|
89
99
|
```
|
|
90
|
-
✅ bg-primary/20, border-
|
|
100
|
+
✅ bg-primary/20, border-default/50, ring-ring/10
|
|
91
101
|
```
|
|
92
102
|
|
|
93
103
|
---
|
|
@@ -109,7 +119,7 @@ Token rules apply **only** to: color (bg, text, border, ring, shadow color), bor
|
|
|
109
119
|
## Rule 4 — Do NOT install or configure these separately
|
|
110
120
|
|
|
111
121
|
```
|
|
112
|
-
❌ Do NOT install or import lucide-react or any icon library — use the package's <Icon /> component (
|
|
122
|
+
❌ Do NOT install or import lucide-react or any icon library — use the package's <Icon /> component (@deriv/quill-icons): <Icon name="bell" weight="bold" />. Catalog + weight conventions: guides/design-system-guide/icon-reference.md
|
|
113
123
|
❌ Do NOT install tailwindcss separately — the package ships its own Tailwind v4 setup
|
|
114
124
|
❌ Do NOT add a tailwind.config.js — configuration is handled by the package
|
|
115
125
|
❌ Do NOT use @apply with hsl(var(--token)) — Tailwind v4 uses CSS variables directly
|
|
@@ -141,20 +151,22 @@ Without this, Tailwind CSS will not process any styles. Next.js projects do NOT
|
|
|
141
151
|
|
|
142
152
|
### Button variants
|
|
143
153
|
```tsx
|
|
144
|
-
<Button variant="primary" /> //
|
|
145
|
-
<Button variant="secondary" /> //
|
|
146
|
-
<Button variant="tertiary" /> // Text only
|
|
154
|
+
<Button variant="primary" /> // Coral filled — main CTA
|
|
155
|
+
<Button variant="secondary" /> // Outline, transparent bg — secondary actions
|
|
156
|
+
<Button variant="tertiary" /> // Text only — minimal
|
|
157
|
+
<Button variant="ghost" /> // Transparent, hover tint — lowest emphasis
|
|
147
158
|
```
|
|
159
|
+
> All buttons are pill-shaped (`rounded-full`) and use `font-display font-extrabold` (800), sentence case.
|
|
148
160
|
|
|
149
161
|
### Badge variants
|
|
150
162
|
```tsx
|
|
151
163
|
// Solid
|
|
152
|
-
<Badge variant="default" /> //
|
|
164
|
+
<Badge variant="default" /> // Brand solid
|
|
153
165
|
<Badge variant="default-success" /> // Green solid
|
|
154
166
|
<Badge variant="default-fail" /> // Red solid
|
|
155
167
|
|
|
156
168
|
// Tint
|
|
157
|
-
<Badge variant="fill" /> //
|
|
169
|
+
<Badge variant="fill" /> // Brand tint bg
|
|
158
170
|
<Badge variant="fill-success" /> // Green tint bg
|
|
159
171
|
<Badge variant="fill-fail" /> // Red tint bg
|
|
160
172
|
|
package/package.json
CHANGED
package/src/styles.css
CHANGED
|
@@ -74,6 +74,26 @@
|
|
|
74
74
|
|
|
75
75
|
--color-warning: var(--text-warning-default);
|
|
76
76
|
--color-info: var(--text-information-default);
|
|
77
|
+
/* Status colour utilities — mirror warning/info: theme-aware, opacity-friendly.
|
|
78
|
+
* `text-success` / `text-error` (status text), `bg-success/10` etc. (status tint). */
|
|
79
|
+
--color-success: var(--text-success-default);
|
|
80
|
+
--color-error: var(--text-error-default);
|
|
81
|
+
/* ── Paired foregrounds for text/icons ON a solid coloured surface ──
|
|
82
|
+
* Use ONLY with the SOLID brand/status colour (bg-primary, bg-success, bg-error,
|
|
83
|
+
* bg-warning, bg-info). On a status *tint* (bg-success/10, bg-[var(--background-success-default)])
|
|
84
|
+
* use the status text colour (text-success / text-error) instead. All resolve to the
|
|
85
|
+
* always-legible static-inverse foreground — additive only, no component is rewired. */
|
|
86
|
+
--color-on-primary: var(--on-prominent-static-inverse);
|
|
87
|
+
--color-on-success: var(--on-prominent-static-inverse);
|
|
88
|
+
--color-on-error: var(--on-prominent-static-inverse);
|
|
89
|
+
--color-on-warning: var(--on-prominent-static-inverse);
|
|
90
|
+
--color-on-info: var(--on-prominent-static-inverse);
|
|
91
|
+
/* Opaque status surfaces (bg-success-surface, bg-error-surface, …) — solid
|
|
92
|
+
* status tints that don't bleed on coloured backgrounds. See LAYER 2A. */
|
|
93
|
+
--color-success-surface: var(--background-success-opaque);
|
|
94
|
+
--color-error-surface: var(--background-error-opaque);
|
|
95
|
+
--color-warning-surface: var(--background-warning-opaque);
|
|
96
|
+
--color-info-surface: var(--background-information-opaque);
|
|
77
97
|
--color-alert-info-text: var(--alert-info-text);
|
|
78
98
|
--color-alert-info-border: var(--alert-info-border);
|
|
79
99
|
--color-alert-error-text: var(--alert-error-text);
|
|
@@ -329,6 +349,13 @@
|
|
|
329
349
|
--color-field-fill-border-focus: var(--field-fill-border-focus);
|
|
330
350
|
--color-field-fill-border-success: var(--field-fill-border-success-focus);
|
|
331
351
|
--color-field-fill-border-error: var(--field-fill-border-error-focus);
|
|
352
|
+
/* Field — inverse variant (input on brand/coloured surfaces) */
|
|
353
|
+
--color-field-inverse-bg-default: var(--field-inverse-bg-default);
|
|
354
|
+
--color-field-inverse-bg-hover: var(--field-inverse-bg-hover);
|
|
355
|
+
--color-field-inverse-bg-focus: var(--field-inverse-bg-focus);
|
|
356
|
+
--color-field-inverse-text: var(--field-inverse-text);
|
|
357
|
+
--color-field-inverse-subtle: var(--field-inverse-subtle);
|
|
358
|
+
--color-field-inverse-border-focus: var(--field-inverse-border-focus);
|
|
332
359
|
/* ── Snackbar colour bridges ── */
|
|
333
360
|
--color-snackbar-bg-default: var(--snackbar-bg-default);
|
|
334
361
|
--color-snackbar-bg-fail: var(--snackbar-bg-fail);
|
|
@@ -757,6 +784,17 @@
|
|
|
757
784
|
--background-pressed-static-light: var(--primitive-slate-alpha-200); /* #181C25 @ 16% */
|
|
758
785
|
--background-primary-canvas: var(--primitive-slate-75); /* #F6F7F8 */
|
|
759
786
|
--background-primary-surface: var(--primitive-slate-50); /* #FFFFFF */
|
|
787
|
+
/* ── Derived opaque status surfaces ──
|
|
788
|
+
* Solid (non-alpha) status tints that read identically on ANY background — no
|
|
789
|
+
* bleed-through when placed over a coloured card/hero (unlike the alpha
|
|
790
|
+
* background-*-default tints). Built with color-mix; inputs are theme-aware so
|
|
791
|
+
* the value recomputes automatically under .dark (lazy custom-property
|
|
792
|
+
* resolution), hence a single :root definition covers both themes. Exposed as
|
|
793
|
+
* bg-success-surface / bg-error-surface / bg-warning-surface / bg-info-surface. */
|
|
794
|
+
--background-success-opaque: color-mix(in oklch, var(--text-success-default) 12%, var(--background-primary-canvas));
|
|
795
|
+
--background-error-opaque: color-mix(in oklch, var(--text-error-default) 12%, var(--background-primary-canvas));
|
|
796
|
+
--background-warning-opaque: color-mix(in oklch, var(--text-warning-default) 12%, var(--background-primary-canvas));
|
|
797
|
+
--background-information-opaque: color-mix(in oklch, var(--text-information-default) 12%, var(--background-primary-canvas));
|
|
760
798
|
--background-secondary-canvas: var(--primitive-slate-50); /* #FFFFFF */
|
|
761
799
|
--background-secondary-surface: var(--primitive-slate-75); /* #F6F7F8 */
|
|
762
800
|
--background-selected-default: var(--primitive-slate-alpha-100); /* #181C25 @ 8% */
|
|
@@ -1111,8 +1149,10 @@
|
|
|
1111
1149
|
/* coral-800 (#E12E3A) — brand hover, same in both themes */
|
|
1112
1150
|
--secondary-hover: var(--background-secondary-surface);
|
|
1113
1151
|
/* TODO PR 3 — replace with button.secondary-normal-bg-hover when component tokens ship */
|
|
1114
|
-
|
|
1115
|
-
|
|
1152
|
+
/* Focus indicator. Figma spec is blue #2c9aff (blue-700), but that is only ~2.93:1 on
|
|
1153
|
+
white; blue-800 #1789e1 keeps the hue and clears WCAG 1.4.11 3:1 in both light
|
|
1154
|
+
(~3.68:1) and dark (~4.08:1). Paired with a 2px ring + 2px surface offset. See issue #38. */
|
|
1155
|
+
--ring: var(--primitive-blue-800);
|
|
1116
1156
|
--overlay: var(--primitive-black-50);
|
|
1117
1157
|
/* TODO — no dedicated overlay foundation token; keeping primitive alias. Revisit when overlay token ships. */
|
|
1118
1158
|
--semantic-error: var(--text-error-default);
|
|
@@ -1218,12 +1258,24 @@
|
|
|
1218
1258
|
@layer base {
|
|
1219
1259
|
* {
|
|
1220
1260
|
border-color: var(--color-default);
|
|
1221
|
-
|
|
1261
|
+
/* Full opacity: a 50% alpha ring fails the 3:1 WCAG 1.4.11 focus-indicator minimum. See issue #38. */
|
|
1262
|
+
outline-color: var(--color-ring);
|
|
1222
1263
|
}
|
|
1223
1264
|
|
|
1224
1265
|
body {
|
|
1225
1266
|
@apply bg-primary-surface text-prominent font-sans antialiased;
|
|
1226
1267
|
}
|
|
1268
|
+
|
|
1269
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1270
|
+
*,
|
|
1271
|
+
*::before,
|
|
1272
|
+
*::after {
|
|
1273
|
+
animation-duration: 0.01ms !important;
|
|
1274
|
+
animation-iteration-count: 1 !important;
|
|
1275
|
+
transition-duration: 0.01ms !important;
|
|
1276
|
+
scroll-behavior: auto !important;
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1227
1279
|
}
|
|
1228
1280
|
|
|
1229
1281
|
/* ── Snackbar: dark mode override via :root.dark (specificity 0,1,1 beats :root 0,0,1) ── */
|
|
@@ -1597,6 +1649,15 @@
|
|
|
1597
1649
|
--field-fill-border-focus: var(--primitive-slate-1200);
|
|
1598
1650
|
--field-fill-border-success-focus: var(--primitive-green-900);
|
|
1599
1651
|
--field-fill-border-error-focus: var(--primitive-red-900);
|
|
1652
|
+
/* Field — inverse: sunken translucent fill for inputs placed ON a brand/coloured
|
|
1653
|
+
* surface (hero cards, banners) where a light fill would blend in. Theme-agnostic
|
|
1654
|
+
* (the surface behind is coloured, not the page), so the light and dark values match. */
|
|
1655
|
+
--field-inverse-bg-default: var(--primitive-black-alpha-400); /* 32% black */
|
|
1656
|
+
--field-inverse-bg-hover: var(--primitive-black-alpha-500); /* 40% black */
|
|
1657
|
+
--field-inverse-bg-focus: var(--primitive-black-alpha-500); /* 40% black */
|
|
1658
|
+
--field-inverse-text: var(--primitive-slate-50); /* white */
|
|
1659
|
+
--field-inverse-subtle: var(--primitive-white-alpha-600); /* 48% white — label/placeholder/icons */
|
|
1660
|
+
--field-inverse-border-focus: var(--primitive-white-alpha-500); /* 40% white */
|
|
1600
1661
|
|
|
1601
1662
|
/* Marker */
|
|
1602
1663
|
--marker-text-asterisk: var(--primitive-red-900);
|
|
@@ -2474,6 +2535,15 @@
|
|
|
2474
2535
|
--field-fill-border-focus: var(--primitive-slate-50);
|
|
2475
2536
|
--field-fill-border-success-focus: var(--primitive-green-500);
|
|
2476
2537
|
--field-fill-border-error-focus: var(--primitive-red-500);
|
|
2538
|
+
/* Field — inverse: sunken translucent fill for inputs placed ON a brand/coloured
|
|
2539
|
+
* surface (hero cards, banners) where a light fill would blend in. Theme-agnostic
|
|
2540
|
+
* (the surface behind is coloured, not the page), so the light and dark values match. */
|
|
2541
|
+
--field-inverse-bg-default: var(--primitive-black-alpha-400); /* 32% black */
|
|
2542
|
+
--field-inverse-bg-hover: var(--primitive-black-alpha-500); /* 40% black */
|
|
2543
|
+
--field-inverse-bg-focus: var(--primitive-black-alpha-500); /* 40% black */
|
|
2544
|
+
--field-inverse-text: var(--primitive-slate-50); /* white */
|
|
2545
|
+
--field-inverse-subtle: var(--primitive-white-alpha-600); /* 48% white — label/placeholder/icons */
|
|
2546
|
+
--field-inverse-border-focus: var(--primitive-white-alpha-500); /* 40% white */
|
|
2477
2547
|
|
|
2478
2548
|
/* Marker */
|
|
2479
2549
|
--marker-text-asterisk: var(--primitive-red-500);
|