diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 4902bf86..9c4eb997 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -95,7 +95,8 @@ const preview: Preview = { options: { storySort: { order: [ - "Introduction", + "Overview", + "Installation", "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..e8776722 --- /dev/null +++ b/src/storybook/Overview.mdx @@ -0,0 +1,82 @@ +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/component-standards.mdx b/src/storybook/component-standards.mdx new file mode 100644 index 00000000..0de27625 --- /dev/null +++ b/src/storybook/component-standards.mdx @@ -0,0 +1,253 @@ +import { Meta } from "@storybook/blocks"; + + + + + +
+ +# Working with components + +Diamond Design System components are built on MUI and adapted for Diamond +scientific software. + +Use MUI components first, then apply Diamond theme roles, variants, states, and +patterns consistently. + +
+ Components should be predictable before they are distinctive. Start with the + standard MUI behaviour, then extend only when there is a reusable Diamond + need. +
+ +## Component breakdown + +Most components can be understood through five layers. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LayerPurposeExample
ComponentThe base UI element + Button, TextField, Alert,{" "} + Card +
VariantThe visual treatment + contained, outlined, text +
IntentThe semantic meaning + primary, secondary, success,{" "} + warning, error, info +
StateThe interaction or system condition + hover, focus, selected,{" "} + disabled, error +
PatternHow the component is used in contextForm field, toolbar action, dialog footer, queue row
+ +## How to use components + +Use existing components and variants before creating custom behaviour. + + + + + + + + + + + + + + + + + + + + + + + + + + +
✅ Prefer❌ Avoid
+ Use MUI props such as variant, color,{" "} + size, and disabled + Restyling components with one-off CSS
Use Diamond semantic theme roles and tokensHardcoded colours, spacing, or shadows
Use standard interaction states consistentlyDifferent hover, focus, or disabled behaviour per screen
Use established layout patternsCreating new arrangements for the same task
+ +## Component standards + +All components should follow these standards: + + + +## Extending an existing component + +Extend an existing component when the base MUI component is right, but Diamond +needs a reusable variation. + +Good reasons to extend include: + + + +Avoid extending a component just to make one screen look different. + +## Creating a new component + +Create a new component only when an existing MUI or Diamond component cannot +support the pattern clearly. + +Before creating one, check: + + + +
+ New components should feel like part of the system from day one. They should + use the same tokens, states, spacing, naming, and interaction logic as + existing components. +
+ +## Naming and scope + +Name components by what they are, not where they first appear. + + + + + + + + + + + + + + + + + + + + + + +
✅ Prefer❌ Avoid
+ ScanStatus + + I18StatusBox +
+ QueueItem + + MappingQueueCard when it is reusable beyond mapping +
+ DeviceConnectionStatus + + BlueButtonPanel +
+ +## Review checklist + +Before adding or changing a component, check: + + + +
diff --git a/src/storybook/practical-guidance.mdx b/src/storybook/practical-guidance.mdx new file mode 100644 index 00000000..fb574b41 --- /dev/null +++ b/src/storybook/practical-guidance.mdx @@ -0,0 +1,1005 @@ +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. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
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.
  • +
+
+
+ +## 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. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RoleMUI mappingPurposeTypical 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: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RoleMUI mappingPurposeTypical 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, },