diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 4902bf86..e0484e39 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -95,7 +95,9 @@ const preview: Preview = { options: { storySort: { order: [ - "Introduction", + "Overview", + "Installation", + "Practical guidance", "Helpers", "Theme", "Theme/Logos", diff --git a/src/storybook/Introduction.mdx b/src/storybook/Installation.mdx similarity index 77% rename from src/storybook/Introduction.mdx rename to src/storybook/Installation.mdx index 71137716..c8454f6f 100644 --- a/src/storybook/Introduction.mdx +++ b/src/storybook/Installation.mdx @@ -1,19 +1,19 @@ -import packageJson from "../../package.json" +import packageJson from "../../package.json"; import { Meta } from "@storybook/blocks"; - +
- # Scientific React UI - v{packageJson.version} + # SciReactUI - v{packageJson.version} ## Introduction - SciReactUI is a collection of useful scientific focused components which utilizing Material UI - to make your React based websites look great. + SciReactUI provides the implementation package for Diamond Design System. - Check out the list of components on the left. To use them, follow the instructions below. + Use this page to install the package, add the theme provider, and start using components in a React application.
+
@@ -30,8 +30,9 @@ import { Meta } from "@storybook/blocks"; ### Next, Add a ThemeProvider - Select a theme, either `GenericTheme` or `DiamondTheme` (Or you can create your own, see below), and add - it to the App via the ThemeProvider: + Select theme `DiamondDSTheme` (or `GenericTheme`), and add it to the App via the ThemeProvider. + + Alternatively, you can fork an existing theme or create your own (see below). ```tsx filename="main.tsx" import { @@ -111,8 +112,8 @@ import { Meta } from "@storybook/blocks"; } ```
- +
@@ -151,4 +152,23 @@ import { Meta } from "@storybook/blocks"; on GitHub.
+
+ + ## Forking the Diamond theme + + If you need the same DiamondDS component behaviour with a different palette, you + can fork `DiamondDSTheme` and provide your own role CSS file instead of + `diamond-ds-roles.css`. + + The theme is designed so most component styling uses semantic roles, not raw + Diamond colours. If your new CSS file defines the same role variables, the + components should continue to work with the new palette. + + For example, replace: + + ```ts + import "../styles/diamondDS/diamond-ds-roles.css"; + ``` +
+
diff --git a/src/storybook/Overview.mdx b/src/storybook/Overview.mdx new file mode 100644 index 00000000..1ef1c977 --- /dev/null +++ b/src/storybook/Overview.mdx @@ -0,0 +1,77 @@ +import { Meta } from "@storybook/blocks"; + + + + + +
+ +# Diamond Design System ❖ + +

+ The design system for Diamond Light Source, providing a shared foundation for + building clear, consistent, and reliable scientific interfaces. +

+ +

+ It evolves SciReactUI into a consistent, semantic, and scalable system for + data acquisition, analysis, and operational tools across Diamond. +

+ +

+ Built on structure and precision, the system supports clear, coherent, and + predictable interfaces across scientific workflows and applications. +

+ +## What it helps us do + + + +## What the design system includes + + + +## Who it is for + +Diamond Design System supports designers, engineers, scientists, and product +teams building operational and experimental software across Diamond. + +The system helps teams create interfaces that feel consistent, predictable, and +safe to use across different tools and beamlines. + +## Principles + +The system focuses on: + + + +## Start here + + +
diff --git a/src/storybook/practical-guidance.mdx b/src/storybook/practical-guidance.mdx new file mode 100644 index 00000000..cb4f8dec --- /dev/null +++ b/src/storybook/practical-guidance.mdx @@ -0,0 +1,1249 @@ +import { Meta } from "@storybook/blocks"; + + + + + +
+ +# Practical guidance + +Diamond Design System uses MUI with Diamond semantic tokens layered on top. + +CSS variables are the source of truth. The MUI theme adapts those tokens for components and implementation. + +## Contents + +
+ +
+ +## Using the theme + +Diamond Design System uses semantic design tokens mapped into MUI’s theme +system. + +CSS variables remain the source of truth. The MUI theme adapts those values into +component APIs, palette roles, typography, spacing, elevation, and interaction +states. + +Prefer theme roles and semantic tokens over hardcoded values. + + + + + + + + + + + + + + + + + + + + + + + + + + +
✅ Prefer❌ Avoid
+ theme.palette.primary.main + + #005bbb +
+ theme.palette.divider + Custom border greys
+ theme.spacing(2) + Arbitrary spacing values
+ surface.subtle + One-off background colours
+ +Using semantic roles keeps interfaces consistent across products, supports light +and dark themes, and allows the system to evolve without rewriting component +styles. + +## Using components + +Build with existing components and patterns before creating new ones. + +Components should keep interfaces predictable, readable, and consistent. + +
+
+

✅ Do

+
    +
  • Reuse established layouts and behaviours.
  • +
  • Use standard component variants consistently.
  • +
  • Keep disabled and error states visually clear.
  • +
  • Use spacing and typography for hierarchy.
  • +
+
+ +
+

❌ Don’t

+
    +
  • Don’t restyle components screen by screen.
  • +
  • Don’t introduce custom colours unnecessarily.
  • +
  • Don’t create multiple patterns for the same interaction.
  • +
  • Don’t override the theme without a reusable reason.
  • +
+
+
+ +## Colour usage + +Use colour semantically. Separate structure, meaning, and brand. + +DiamondDS supports: + +- action intents: primary, secondary +- status intents: success, warning, error, info + +Intent colours communicate hierarchy, operational meaning, and state through component APIs such as `color="primary"` or `color="error"`. +Their meaning depends on context and workflow. + +Brand colour is intentionally separate. Brand communicates Diamond identity rather than behaviour or status. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Token/RoleTypePurposeTypical usage
+ + Neutral + StructureLayout and hierarchyBackgrounds, surfaces, borders, tables
+ + Primary + Action intentMain actions and emphasisPrimary actions, selected states
+ + Secondary + Action intentSupporting actions and alternate emphasisSecondary actions, filters, supporting controls
+ + Success + Status intentConfirmed, available, or operationally valid statesCompletion, confirmation, active or valid states
+ + Warning + Status intentAttention, caution, or elevated operational awarenessRisk states, hazardous conditions, attention-required states
+ + Error (Danger) + Status intentCritical, blocking, hazardous, or destructive statesErrors, failed actions, emergency-related or destructive actions
+ + Info + Status intentInformational, contextual, or progress-related feedbackProgress, guidance, scanning, movement, or system messages
+ + Brand + IdentityFacility identityBranding moments and facility identity
+ +
+
+

✅ Do

+
    +
  • Use neutral roles for structure.
  • +
  • Use intent roles for meaning.
  • +
  • Use theme.palette or MUI component props so colours work across light and dark themes.
  • +
  • Ensure disabled and error states override hover, focus and selected styling.
  • +
+
+ +
+

❌ Don’t

+
    +
  • Don’t hardcode hex values in components.
  • +
  • Don’t use strong intent colours as layout backgrounds.
  • +
  • Don’t rely on colour alone to communicate state.
  • +
  • Don’t invent one-off colour behaviour outside the theme.
  • +
+
+
+ +### Semantic intent and brand roles + +Intent and brand colours follow a shared semantic structure. +Each role includes related tokens for emphasis, contrast, containers, and interactive states. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Token patternMUI rolePurposeTypical use
+ --ds-[token] + + palette.[role].main + Main semantic colourActions, status communication, emphasis, identity
+ --ds-on-[token] + + palette.[role].contrastText + Foreground colour paired with the roleText and icons shown on the role colour
+ --ds-[token]-emphasis + + palette.[role].dark + Stronger variation of the roleHover, active, or stronger emphasis states
+ --ds-[token]-accent + + palette.[role].light + Lighter accent variationFocus rings, highlights, supporting accents
+ --ds-[token]-container + + palette.[role].container + Lower-emphasis role surfaceChips, alerts, selected regions, grouped states
+ --ds-on-[token]-container + + palette.[role].onContainer + Foreground colour paired with role containersText and icons inside semantic containers
+ --ds-[token]-solid + + palette.[role].solid + High-emphasis interactive surfaceContained buttons and strong interactive controls
+ --ds-on-[token]-solid + + palette.[role].onSolid + Foreground colour paired with solid surfacesText and icons inside solid controls
+ +
+

Token names and MUI role names are usually aligned.

+

+ DiamondDS uses danger tokens internally, which map to the MUI + error palette role. +

+
+ +### Neutral roles + +Neutral tokens create the structure of the interface. +They should be the default choice for layout, surfaces, borders, text, and dense scientific workflows. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TokenMUI rolePurposeTypical use
+ --ds-background + + background.default + Root application backgroundApp shell, page canvas, full-screen layouts
+ --ds-surface + + background.paper + Base content surfaceCards, dialogs, menus, content panels
+ --ds-surface-container + + surface.subtle + Quiet grouped surfaceSecondary panels, grouped controls, low-emphasis regions
+ --ds-surface-container-high + + surface.strong + Stronger grouped surfaceNested containers, selected regions, raised sections
+ --ds-surface-disabled + + surface.disabled + Disabled surface treatmentDisabled filled controls and inactive regions
+ --ds-on-surface + + text.primary + Main foreground colourPrimary text and icons
+ --ds-on-surface-variant + + text.secondary + Lower-emphasis foreground colourSecondary text, metadata, helper text
+ --ds-on-surface-disabled + + text.disabled + Disabled foreground colourDisabled text and icons
+ --ds-action-disabled + + action.disabled + Disabled interactive colourDisabled buttons, controls, and actions
+ --ds-border-subtle + + borders.base + Quiet structural boundaryDividers, table lines, subtle outlines
+ --ds-border-emphasis + + borders.emphasis + Stronger boundaryInteractive boundaries and active regions
+ --ds-border-strong + + borders.strong + Highest-emphasis neutral boundaryHover states and strong affordance boundaries
+ +## Surfaces and elevation + +Surfaces create structure and hierarchy. They should help users understand +where content belongs without making dense scientific interfaces feel noisy. + +Prefer layered surfaces and borders over heavy shadows. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TokenMUI rolePurposeTypical use
+ --ds-bg-page + + background.default + Root application backgroundApp shell, page canvas, full-screen layouts
+ --ds-surface + + background.paper + Base content surfaceCards, dialogs, menus, popovers, standard content panels
+ --ds-surface-container + + surface.subtle + Quiet container surfaceSecondary panels, grouped content, low-emphasis regions
+ --ds-surface-container-high + + surface.strong + Stronger container surfaceRaised sections, selected regions, nested containers
+ --ds-surface-disabled + + surface.disabled + Disabled surface treatment + Disabled filled controls, inactive regions where a surface still needs + to be visible +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ElementRecommended treatment
Top nav bar + Elevation 0 + border-bottom. Elevate to 1–2 on scroll when sticky and no + secondary nav is present +
SidebarElevation 0 + border-right
Secondary header/nav barElevation 1. Elevate to 1–2 on scroll when sticky
Cards + Elevation 0-2 + subtle border, or no border when the surface is already + clear +
Interactive cardsElevation 3–4, such as drag/drop cards
Menus, popovers, drawersElevation 8–16
DialogsElevation 16–24
+ +
+
+

✅ Do

+
    +
  • Use background.default for the application canvas.
  • +
  • Use background.paper for primary content areas.
  • +
  • Use surface.subtle to group related content.
  • +
  • Use surface.strong for stronger grouping or selected regions.
  • +
  • Use surface changes consistently across light and dark mode.
  • +
+
+ +
+

❌ Don’t

+
    +
  • Don’t use strong intent colours as general layout backgrounds.
  • +
  • Don’t stack too many nested surface colours.
  • +
  • Don’t use surface changes to compensate for unclear layout.
  • +
  • Don’t create one-off background colours for individual components.
  • +
  • Don’t make disabled surfaces look interactive.
  • +
+
+
+ +## Borders + +Borders define separation, grouping and affordance. They should support structure without creating visual noise. + +Use border roles instead of raw greys: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TokenMUI rolePurposeTypical use
+ --ds-border-subtle + + divider + / +
+ border.subtle +
Default quiet borderDividers, table separators, low-emphasis boundaries
+ --ds-border-emphasis + + border.emphasis + Elevated interaction/emphasisInputs, highlighted cards, panels, tables, important grouping
+ --ds-border-strong + + border.strong + Maximum border contrastHover states, active regions, selected-neutral
+ +MUI’s native divider role and DiamondDS border.subtle use the same value. +Use divider where a MUI component expects it, and border.subtle when writing DiamondDS border styles directly. + +
+
+

✅ Do

+
    +
  • Use border.subtle for quiet dividers, separators, table boundaries, and disabled outlines.
  • +
  • Use border.emphasis for interactive component boundaries and elements that require clearer affordance.
  • +
  • Use border.strong for elevated interaction states such as hover, active, or selected elements.
  • +
  • Use intent border colours only for meaningful states such as error or selected.
  • +
  • Let disabled and error borders override hover and focus styling.
  • +
+
+ +
+

❌ Don’t

+
    +
  • Don’t use raw grey values for component borders.
  • +
  • Don’t use borders as the only way to communicate status.
  • +
  • Don’t add heavy borders to compensate for weak spacing or grouping.
  • +
  • Don’t mix several border strengths in the same small area.
  • +
  • Don’t invent one-off border colours outside the theme.
  • +
+
+
+ +## Typography usage + +Typography should support readability, scanning, and technical clarity. + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypefacePurposeTypical usage
InterDefault interface typefaceUI text, controls, tables, navigation
OutfitBrand and high-level headingsProduct headings, landing areas
IBM Plex MonoTechnical and aligned contentIDs, timestamps, code, numeric values
+ +
+
+

✅ Do

+
    +
  • Keep hierarchy consistent across products.
  • +
  • Prefer short, clear labels.
  • +
  • Make numbers and technical values easy to scan.
  • +
  • Use mono type where alignment matters.
  • +
+
+ +
+

❌ Don’t

+
    +
  • Don’t use brand typography for dense operational content.
  • +
  • Don’t rely on decorative styling for hierarchy.
  • +
  • Don’t hide important information in faint text.
  • +
  • Don’t introduce one-off font sizes.
  • +
+
+
+ +## General principles + + + +## Button hierarchy and pairing + +
+ Button hierarchy should make the next safe action obvious. Avoid placing + multiple high-emphasis actions next to each other unless they genuinely have + equal priority. +
+ +### Default pairing + +Use one contained button for the main action, then reduce emphasis for nearby +supporting actions. + +### Recommended patterns + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PatternUse whenRecommended pairing
Main action + cancelThe user needs a clear way to proceed or back out + primary contained + text +
Main action + supporting actionThe second action helps prepare or configure the main action + primary contained + outlined +
Main action + more actionsAdditional actions are available but should not compete + primary contained + menu button +
Destructive confirmationThe user is confirming a destructive or irreversible action + error contained + neutral text or{" "} + outlined +
Promoted secondary workflowA secondary action is intentionally more useful in context + Lower-emphasis primary action + secondary contained +
+ +
+
+

✅ Do

+
    +
  • Use one high-emphasis action in a local action group.
  • + +
  • + Use text buttons for cancel, dismiss, and low-risk exits. +
  • + +
  • + Use menu buttons for overflow actions that should not compete visually. +
  • + +
  • + Use destructive emphasis only when the action is genuinely destructive + or hazardous. +
  • +
+ +
+ +
+

❌ Don’t

+
    +
  • + Don’t place primary contained and + secondary contained next to each other by default. +
  • + +
  • + Don’t use multiple contained buttons to solve unclear priority. +
  • + +
  • + Don’t make cancel actions visually compete with the main action. +
  • + +
  • + Don’t promote secondary actions just for visual variety. +
  • +
+ +
+
+ +## Feedback and status + +
+ Interfaces should continuously communicate system state, progress, success, + warnings, and problems. Clear feedback helps users understand what is + happening, what requires attention, and whether it is safe to continue. +
+ +### Communicate state clearly + +Provide feedback for important actions, transitions, and system events. + +Users should understand: + + + +Avoid relying on colour alone. Combine colour with labels, icons, text, or +layout changes where appropriate. + +--- + +### Status intent meanings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusPurposeTypical usage
+ + Success + Positive or valid outcomeCompleted actions, successful operations, valid system state
+ + Warning + Caution or attention requiredRisk states, interruptions, unusual conditions, partial issues
+ + Error/Danger + Critical issue or failed actionValidation failures, failed operations, destructive actions
+ + Info + Informational or transitional stateProgress updates, guidance, active processes, system messages
+ +--- + +### Progress and transitional states + +Use informational feedback for active or changing system states. + +Examples include: + + + +Prefer persistent inline or contextual feedback over temporary notifications for +long-running operations. + +--- + +### Success feedback + +Use success feedback sparingly. + +Not every successful action requires a notification. + +Prefer lightweight confirmation for routine actions, especially in repetitive +scientific workflows. + + + + + + + + + + + + + + + + + + + + + + +
✅ Prefer❌ Avoid
Quiet inline confirmation after savingLarge celebratory success states for routine operations
Small status update in a queue or table rowStacking repeated success toasts during repetitive workflows
Temporary confirmation for destructive actionsInterrupting workflow with unnecessary success messaging
+ +--- + +## Errors and recovery + +
+ Error handling should help users recover safely and confidently. Focus on + clarity, next steps, and preventing further mistakes. +
+ +### Make errors actionable + +Good error messages explain: + + + +Avoid vague or technical-only messaging where possible. + + + + + + + + + + + + + + + + + + + + + + +
❌ Avoid✅ Prefer
+ Operation failed + + Unable to connect to detector +
+ Validation error + + Exposure time must be greater than 0 +
+ Device unavailable + + + Motor controller is offline. Reconnect or contact beamline staff. + +
+ +--- + +### Prefer recovery over dead ends + +Where possible, help users continue safely. + +Provide: + + + +Avoid trapping users in blocked states without explanation. + +--- + +### Error severity + +Not all errors require the same visual weight. + + + + + + + + + + + + + + + + + + + + + + +
SeverityTypical treatment
MinorInline validation or local helper text
ModerateInline alert, panel warning, persistent message
CriticalBlocking alert, dialog, or operational interruption
+ +--- + +### Safety and operational awareness + +In scientific and operational environments, errors may affect hardware, +beamtime, experiments, or data integrity. + +Use stronger emphasis when actions may: + + + +Destructive or irreversible actions should require clear confirmation and should +never compete visually with safe actions. + +
diff --git a/src/styles/diamondDS/diamond-ds-roles.css b/src/styles/diamondDS/diamond-ds-roles.css index 2ccf5815..ff49288d 100644 --- a/src/styles/diamondDS/diamond-ds-roles.css +++ b/src/styles/diamondDS/diamond-ds-roles.css @@ -51,8 +51,8 @@ --ds-placeholder-focus: var(--ds-grey-700); --ds-border-subtle: var(--ds-grey-300); - --ds-border: var(--ds-grey-400); - --ds-border-emphasis: var(--ds-grey-500); + --ds-border-emphasis: var(--ds-grey-400); + --ds-border-strong: var(--ds-grey-500); --ds-border-subtle-channel: 221 225 232; /* Interaction overlays diff --git a/src/themes/DiamondDSTheme.ts b/src/themes/DiamondDSTheme.ts index 23e81f57..0042c2be 100644 --- a/src/themes/DiamondDSTheme.ts +++ b/src/themes/DiamondDSTheme.ts @@ -186,10 +186,10 @@ declare module "@mui/material/styles" { brand?: BrandPaletteColor; /** Neutral border roles used for structure, not meaning. */ - borders: { + border: { subtle: string; - base: string; emphasis: string; + strong: string; }; /** Neutral surface roles used to create hierarchy without semantic state. */ @@ -216,10 +216,10 @@ declare module "@mui/material/styles" { interface PaletteOptions { brand?: BrandPaletteOptions; - borders?: { + border?: { subtle?: string; - base?: string; emphasis?: string; + strong?: string; }; surface?: { subtle?: string; @@ -514,13 +514,22 @@ const createDiamondPalette = (mode: DSMode) => { paper: "rgb(var(--ds-surface-channel))", }, + /** + * Divider and border roles describe structure and separation, not meaning. + * + * Divider is the default border role for general structure and separatio. + * Border.subtle is a semantic utlisity role for components that need to reference a border colour directly. + * Border.emphasis is a emphasised border role for actionable elements and highlighted states. + * Border.strong is a stronger border role for hover and focus states. + * + */ divider: "var(--ds-border-subtle)", dividerChannel: "var(--ds-border-subtle-channel)", - borders: { - subtle: "var(--ds-border-subtle)", - base: "var(--ds-border)", + border: { + subtle: "var(--ds-border)", emphasis: "var(--ds-border-emphasis)", + strong: "var(--ds-border-strong)", }, surface: { @@ -746,7 +755,7 @@ const DiamondDSTheme = extendTheme({ "&.Mui-disabled": { ...getDisabledControlStyles(), - borderColor: "var(--ds-border-subtle)", + borderColor: "var(--ds-border)", }, }; } @@ -835,10 +844,10 @@ const DiamondDSTheme = extendTheme({ styleOverrides: { root: ({ theme }: ThemeOnlyArgs): CSSObject => ({ textTransform: "none", - border: `1px solid ${theme.palette.borders.base}`, + border: `1px solid ${theme.palette.border.emphasis}`, "&:hover": { - borderColor: theme.palette.borders.emphasis, + borderColor: theme.palette.border.strong, }, "&.Mui-selected": { @@ -855,7 +864,7 @@ const DiamondDSTheme = extendTheme({ "&.Mui-disabled": { color: "var(--ds-on-surface-disabled)", - borderColor: "var(--ds-border-subtle)", + borderColor: "var(--ds-border)", }, }), }, @@ -888,7 +897,7 @@ const DiamondDSTheme = extendTheme({ ...(isInteractive ? getFocusOutline() : {}), color: "var(--ds-on-surface)", - borderColor: "var(--ds-border)", + borderColor: "var(--ds-border-emphasis)", backgroundColor, ...(isInteractive && { @@ -1039,12 +1048,12 @@ const DiamondDSTheme = extendTheme({ return { "& .MuiOutlinedInput-notchedOutline": { - borderColor: theme.palette.borders.base, + borderColor: theme.palette.border.emphasis, }, "&:hover:not(.Mui-disabled):not(.Mui-error):not(.Mui-focused) .MuiOutlinedInput-notchedOutline": { - borderColor: theme.palette.borders.emphasis, + borderColor: theme.palette.border.strong, }, "&.Mui-focused:not(.Mui-disabled):not(.Mui-error) .MuiOutlinedInput-notchedOutline": @@ -1079,7 +1088,7 @@ const DiamondDSTheme = extendTheme({ }, "&.Mui-disabled .MuiOutlinedInput-notchedOutline": { - borderColor: "var(--ds-border-subtle)", + borderColor: "var(--ds-border)", }, }; }, @@ -1214,7 +1223,7 @@ const DiamondDSTheme = extendTheme({ ...common, backgroundColor: p.container, color: p.onContainer, - border: "1px solid var(--ds-border-subtle)", + border: "1px solid var(--ds-border)", }; }, }, @@ -1302,7 +1311,7 @@ const DiamondDSTheme = extendTheme({ root: { backgroundColor: "var(--ds-surface-container)", color: "var(--ds-on-surface)", - border: "1px solid var(--ds-border-subtle)", + border: "1px solid var(--ds-border)", borderRadius: 8, },