企业软件 · 新资源

HPE Grommet 设计系统.

使用 Grommet 的布局基元、受控表单字段和数值仪表来构建容量预留界面。谨慎使用其主题比例,并将 Grommet 基础主题与单独安装的 HPE 主题区分开来。

OpenDesign 指南9 个章节38 条参考条目原始应用指南
01

HPE Grommet 设计系统界面预览

调整拟定的资源分配,并生成经过验证的本地方案。

容量预留规划器打开完整示例
对 Grommet 基础尺寸和颜色进行独立的 HTML/CSS 解读,并明确选择 Arial 字体;这不是单独的 HPE 主题。 · 实现参考
02

HPE Grommet 设计系统设计参考

使用 baseSpacing=24 和 scale=6 生成的 Grommet v2 基础主题;这些并非 grommet-theme-hpe 的值。原生起始项目明确将 Arial 以及所示的品牌色和焦点色设为应用主题选项。

默认边缘尺寸比例

来源
名称 / 规则值 / 配置用途
global.edgeSize.hair1px小屏响应式覆盖之外的默认尺寸。
global.edgeSize.xxsmall3px小屏响应式覆盖之外的默认尺寸。
global.edgeSize.xsmall6px小屏响应式覆盖之外的默认尺寸。
global.edgeSize.small12px小屏响应式覆盖之外的默认尺寸。
global.edgeSize.medium24px小屏响应式覆盖之外的默认尺寸。
global.edgeSize.large48px小屏响应式覆盖之外的默认尺寸。
global.edgeSize.xlarge96px小屏响应式覆盖之外的默认尺寸。

小屏响应式覆盖

来源
名称 / 规则值 / 配置用途
global.breakpoints.small.value768基础主题中的小屏断点边界。
small.edgeSize.xxsmall2px小屏精细间距。
small.edgeSize.xsmall3px小屏超小间距。
small.edgeSize.small6px响应式小号内边距。
small.edgeSize.medium12px响应式中号内边距。
small.edgeSize.large24px响应式大号内边距。
global.breakpoints.medium.value1536下一个基础断点边界。

基础颜色与控件

来源
名称 / 规则值 / 配置用途
global.colors.brand#7D4CDB Grommet 默认品牌色,不是 HPE 绿色。
global.colors.focus#6FFFB0 默认焦点强调色。
global.colors.text.light#444444 浅色主题正文文本。
global.colors.text.dark#f8f8f8 深色主题正文文本。
global.colors.background-front.light#FFFFFF 前景浅色表面。
global.colors.background-front.dark#444444 前景深色表面。
global.control.border.radius4px基础控件圆角。
global.control.border.width1px基础控件边框。

表单与字段约定

来源
名称 / 规则值 / 配置用途
Form.valueObject keyed by field name使用单个受控的预订对象。
Form.onChange(value) => {}接收更新后的对象,而不是 DOM 事件。
Form.onSubmit({ value, touched }) => {}读取已接受的当前表单值。
Form.validateblur | submit | change选择验证的触发时机。
Form.errorsObject keyed like value将远程或应用层错误关联到字段。

Select 与范围控件的集成

来源
名称 / 规则值 / 配置用途
Select.optionsString array or object array示例使用字符串,让值的结构更简单。
Select.onChange({ value, option }) => {}不要通过 Select 的 event.target.value 读取值。
Select.valueKey{ key, reduce } for object optionsreduce 返回键对应的值,而不是完整对象。
Select.labelKeyProperty name or function对象选项的可见标签。
Select.onSearchFunction; enables search input需要时,由应用提供筛选逻辑。

Meter 的组成

来源
名称 / 规则值 / 配置用途
valuenumber表示的数值;如果提供了 values,则忽略此项。
maxnumber or numeric string可用总容量;不要将其误认为百分比。
typebar | circle | pie | semicircle使用 circle 展示使用率概览。
colorColor identifier单个值时有效。
a11yTitlestring说明度量值及其分母。
sizeNamed size or CSS dimension让环形图保持在可用宽度之内。
03

HPE Grommet 设计系统完整指南

实用指南,介绍如何为真实界面选择、应用和评审此系统。

DESIGN-hpe-grommet.md

完整指导、实现起点和源代码链接。

下载指南

HPE Grommet 设计系统:以 Grommet 和 HPE 主题为基础

不要将紫色标记为 HPE 设计令牌

Grommet 是一个与 HPE 相关的 React 框架,拥有自己的基础主题。独立的 grommet-theme-hpe 包会导出 hpe,供采用 HPE 设计风格的应用使用。本参考介绍基础框架和明确配置的示例。其紫色品牌色和薄荷色焦点色来自基础主题,并非当前 HPE 品牌配色。

摘自本 OpenDesign 指南

阅读配套规范

简洁明确的应用主题

此设置将 Arial 设为应用字体,并沿用文档中说明的基础品牌色和焦点色。其他所有组件规则均继承自 Grommet。实际的 HPE 产品可以改为传入经批准的 hpe 主题;之后请核对最终的间距和字体排版,因为主题覆盖可能会改变此处列出的基础值。

阅读配套规范

HPE Grommet 设计系统主题比例值可能会在断点处变化

命名值也是响应式设计决策

基础生成器从 24 像素开始。默认的中等边缘间距为 24px,但在小屏断点处,中等间距会变为 12px。因此,即使 JSX 中仍写着 medium,使用响应式内边距的 Box 也可能缩小。请结合比例值与断点覆盖规则一起查看;不要保证 medium 始终为二十四像素。

阅读配套规范

使用 Box 实现实际布局

此规划器使用纵向 Box 作为页面布局,并使用响应式横向/纵向 Box 排列表单和容量摘要。表单子项可以扩展,而摘要则保留实用的最小宽度。在小屏幕上,图表会排在控件之后,与文档顺序一致。

阅读配套规范

HPE Grommet 设计系统:明确指定的易读基础样式

字号和行高是独立的主题值

基础生成器根据间距输入值生成 18 像素字号和 24 像素行高。示例明确使用这组数值和 Arial,避免让人误以为下载了专有品牌字体。标题使用 Grommet Heading,正文使用 Text,由主题解析它们的角色,而不是在 CSS 中重复实现组件内部样式。

阅读配套规范

HPE Grommet 设计系统:单个受控的预订对象

字段名称将字段与表单关联起来

Form 负责协调表单约定。在受控模式中,value 和 onChange 由调用方提供。每个 FormField 及其子输入上的 name 都用于标识对应的值键。我们的预订对象包含 name 和 pool。容量滑块单独保存为一个数字,因为它会在提交前驱动实时图表。

阅读配套规范

验证预订名称

阅读配套规范

HPE Grommet 设计系统:Select 有自己的事件结构

使用字符串让简单场景更可预测

示例中的选项池为 Production 和 Development,因此受控值是字符串。如果改用对象选项,请设置 labelKey,并可选择通过 reduce 设置 valueKey,然后确保存储值与该选择一致。Select 的 onChange 会提供一个包含 value/option 的对象,不同于原生范围输入事件。

阅读配套规范

搜索和选项加载由应用负责

提供 onSearch 时,Select 可以显示搜索框。这个属性并不意味着所有选项都会自动筛选。请单独保留未筛选的源集合,以便关闭或清除搜索后恢复。对于两个选项池,本示例特意省略了搜索功能。

阅读配套规范

HPE Grommet 设计系统:Meter 需要单位和分母

表示容量,而不是一个含义不明的百分比

Meter 接收预计使用量,并设置 max=100。在这个示例规划器中,样例选项池已使用 35 个单位,拟预订量的范围为 5 到 60。由于演示中的分母是 100,百分比恰好与数值相同。代码仍会明确传入 max,这样即使总量改变,数据约定也能保持不变。

阅读配套规范

保持图表与文本同步

环形图、预计使用量标签和剩余单位数都根据同一个数字滑块值计算。原生 RangeInput 会发出 DOM 事件,因此在进行算术运算前,请将 event.target.value 转换为 Number。否则,将字符串与三十五相加可能会得到看似合理但实际错误的总量。

阅读配套规范

HPE Grommet 设计系统:文档滚动与窄屏布局

本页面选择 full="min"

Grommet 的 full=true 适用于自行控制视口和内部滚动的应用。本规划器使用 full="min",让文档可以随内容延长。这样可避免表单及其验证消息在手机上被困在固定高度的外壳中。

阅读配套规范

在 Grommet 内部读取 ResponsiveContext

子组件会读取当前上下文,并在小屏幕上选择纵向布局,在其他情况下选择横向布局。提供程序必须包裹该子组件,确保上下文对应所选主题。可用宽度较窄时,备用布局仍会自然地采用纵向排列。

  • 将字段标签放在输入控件上方。
  • 在源码顺序中,将容量摘要放在控件之后。
  • 允许操作行换行,同时避免隐藏验证文本。

阅读配套规范

HPE Grommet 设计系统:关联标签、错误和用量

为每个数值显示明确含义

范围控件始终显示标签和单位。圆形仪表会收到包含预计用量和总容量的 a11yTitle。附近的文本也会显示相同数值,因此信息不会只通过彩色圆弧传达。错误提示会指出预留问题,并显示在对应字段旁。

阅读配套规范

明确说明本地操作结果

  1. 提交空白名称,确认出现必填字段错误。
  2. 输入名称、选择资源池并调整分配量。
  3. 准备方案,并确认本地快照包含所选资源池和数值单位。

阅读配套规范

HPE Grommet 设计系统:挂载完整的 Grommet 组合

安装框架及其样式对等依赖

在客户端项目中安装 grommet、styled-components 和 React 运行时。此设置会挂载 Grommet,以及使用 ResponsiveContext 的子组件、受控 Form、FormField/TextInput/Select、RangeInput 和 Meter。使用 Button 的 label 属性而非 children,明确采用默认的标签样式按钮行为。

阅读配套规范

HPE Grommet 设计系统组件示例

完整的独立交互示例

将完整文档保存为 index.html 并在浏览器中打开。这是对基础 Grommet 尺寸和颜色的独立 HTML/CSS 解读,并明确选用 Arial 字体;不是单独的 HPE 主题。

html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Capacity reservation — Grommet study</title><style>*{box-sizing:border-box}body{margin:0;background:white;color:#444;font:18px/24px Arial,sans-serif}header{padding:24px 36px;border-bottom:1px solid #ddd;display:flex;gap:12px;align-items:center}.mark{width:22px;height:22px;border:4px solid #7d4cdb;border-radius:50%}main{max-width:1050px;margin:auto;padding:36px}h1{font-size:36px;line-height:42px;margin:12px 0 24px;color:#222}h2{font-size:24px;line-height:30px;margin:0 0 12px}.intro{max-width:650px;margin-bottom:36px}.layout{display:grid;grid-template-columns:minmax(0,1fr) 310px;gap:48px}label{display:block;font-weight:600;margin-bottom:12px}input,select,button{font:inherit;max-width:100%}input[type=text],select{width:100%;border:1px solid #888;border-radius:4px;background:transparent;padding:12px;color:#444}input:focus-visible,select:focus-visible,button:focus-visible{outline:3px solid #6fffb0;outline-offset:3px}.field{margin-bottom:24px}input[type=range]{width:100%;accent-color:#7d4cdb}.limits{display:flex;justify-content:space-between;font-size:14px;color:#666;margin-top:6px}button{border:2px solid #7d4cdb;border-radius:24px;background:#7d4cdb;color:white;padding:10px 24px;font-weight:600;cursor:pointer}button:hover{background:#6839c0}aside{background:#f2f2f2;padding:24px;border-radius:12px;align-self:start;text-align:center}.ring{width:192px;height:192px;border-radius:50%;background:conic-gradient(#7d4cdb var(--used),#dadada 0);margin:24px auto;display:grid;place-items:center;position:relative}.ring:before{content:'';position:absolute;inset:12px;background:#f2f2f2;border-radius:50%}.ring span{position:relative;font-size:36px;font-weight:bold}.ring small{display:block;font-size:14px;font-weight:400;line-height:20px}.legend{text-align:left;border-top:1px solid #ddd;padding-top:12px;font-size:14px}.legend div{display:flex;justify-content:space-between;margin:8px 0}.error{font-size:14px;color:#b30000;margin-top:6px}#result{background:#f2f2f2;border-left:4px solid #7d4cdb;padding:24px;margin-top:36px}footer{font-size:12px;line-height:18px;color:#666;border-top:1px solid #ddd;padding:24px 36px}@media(max-width:700px){main{padding:24px}.layout{grid-template-columns:1fr;gap:24px}h1{font-size:30px;line-height:36px}header,footer{padding:24px}.intro{margin-bottom:24px}}</style><header><span class="mark" aria-hidden="true"></span><strong>Capacity planner</strong></header><main><h1>Plan a reservation</h1><p class="intro">Explore a proposed allocation before preparing a local plan. This model contains 100 capacity units.</p><div class="layout"><form id="form" novalidate><div class="field"><label for="name">Reservation name</label><input id="name" type="text" required aria-describedby="error"><div class="error" id="error" hidden></div></div><div class="field"><label for="pool">Capacity pool</label><select id="pool"><option>Production</option><option>Development</option></select></div><div class="field"><label for="units">Requested allocation: <output id="requested">20</output> units</label><input id="units" type="range" min="5" max="60" step="5" value="20"><div class="limits"><span>5 units</span><span>60 units</span></div></div><button type="submit">Prepare plan</button><p style="font-size:14px;color:#666">No infrastructure will be provisioned.</p></form><aside><h2>Projected usage</h2><div class="ring" id="ring" style="--used:55%" role="img" aria-label="55 of 100 units projected usage"><span><output id="used">55</output><small>of 100 units</small></span></div><div class="legend"><div><span>Already used</span><strong>35</strong></div><div><span>Proposed reservation</span><strong id="proposed">20</strong></div><div><span>Remaining</span><strong id="remaining">45</strong></div></div></aside></div><section id="result" hidden><h2>Prepared local plan</h2><p id="snapshot" role="status"></p><p style="font-size:14px">This snapshot changes only when you prepare the plan again.</p></section></main><footer>Independent base Grommet HTML/CSS interpretation. Base purple/mint palette and spacing; Arial is an application font choice. This is not the separate HPE branded theme.</footer><script>
const $=id=>document.getElementById(id);$('units').oninput=()=>{const units=Number($('units').value),used=35+units;$('requested').textContent=$('proposed').textContent=units;$('used').textContent=used;$('remaining').textContent=100-used;$('ring').style.setProperty('--used',used+'%');$('ring').setAttribute('aria-label',used+' of 100 units projected usage')};$('form').onsubmit=e=>{e.preventDefault();const name=$('name').value.trim();if(name.length<3){$('error').textContent='Use at least three characters for the reservation name.';$('error').hidden=false;$('name').setAttribute('aria-invalid','true');$('name').focus();return}$('error').hidden=true;$('name').removeAttribute('aria-invalid');$('snapshot').textContent=name+' · '+$('pool').value+' · '+$('units').value+' units. Prepared in this local demonstration.';$('result').hidden=false};
</script></html>

代码参考

  • 容量计算使用示例中显示的资源池数据。独立布局 HTML;原生示例选用基础 Grommet,而非单独的 HPE 主题。

完整的原生实现入口

此处汇总了从设置到完整实现的内容,并附有重点说明 API。请按照设置中的文档说明,满足软件包和构建前置条件。

jsx
// npm install react react-dom grommet styled-components
import React, { useContext, useState } from 'react';
import { createRoot } from 'react-dom/client';
import { Grommet, Box, Heading, Text, Form, FormField, TextInput,
 Select, RangeInput, Meter, Button, ResponsiveContext } from 'grommet';
const theme={global:{font:{family:'Arial, sans-serif',size:'18px',height:'24px'},colors:{brand:'#7D4CDB',focus:'#6FFFB0'}}};
function Planner(){
 const size=useContext(ResponsiveContext);
 const [value,setValue]=useState({name:'',pool:'Production'});
 const [units,setUnits]=useState(20),[plan,setPlan]=useState(null);
 const used=35+units;
 return <Box pad="medium" gap="medium" width={{max:'large'}} margin="auto">
 <Heading level={1} margin="none">Plan a reservation</Heading>
 <Text>Local capacity model. No infrastructure is provisioned.</Text>
 <Box direction={size==='small'?'column':'row'} gap="large">
 <Box flex><Form value={value} onChange={setValue} validate="submit" onSubmit={({value:accepted})=>setPlan({...accepted,units})}>
 <FormField name="name" htmlFor="reservation-name" label="Reservation name" required validate={name=>String(name || '').trim().length<3?'Use at least three characters':undefined}>
 <TextInput name="name" id="reservation-name"/></FormField>
 <FormField name="pool" htmlFor="pool" label="Capacity pool"><Select name="pool" id="pool" options={['Production','Development']}/></FormField>
 <Box gap="small" margin={{vertical:'medium'}}><label htmlFor="units">Requested allocation: {units} units</label>
 <RangeInput id="units" min={5} max={60} step={5} value={units} onChange={event=>setUnits(Number(event.target.value))}/></Box>
 <Button type="submit" primary label="Prepare plan"/>
 </Form></Box>
 <Box align="center" gap="small" pad="medium" background="light-2" round="small">
 <Meter type="circle" value={used} max={100} size="small" thickness="small" color="brand" a11yTitle={`${used} of 100 units projected usage`}/>
 <Text weight="bold">{used} / 100 units used</Text><Text>{100-used} units remaining</Text>
 </Box></Box>
 {plan&&<Box background="light-2" pad="medium" role="status"><Text>Local plan: {plan.name} · {plan.pool} · {plan.units} units</Text></Box>}
 </Box>
}
createRoot(document.getElementById('root')).render(<Grommet theme={theme} themeMode="light" full="min"><Planner/></Grommet>);

代码参考

  • 适用于包含根元素的项目的客户端 main.jsx。使用基础 Grommet,并明确声明应用字体和品牌覆盖样式。不默认启用 HPE 主题。API 已根据官方文档核对;此处尚未验证原生编译。

有意切换为 HPE 品牌主题

仅在目标设计确实需要时使用单独的程序包;请根据已安装的版本重新核对取值。

jsx
// npm install grommet-theme-hpe
import { Grommet } from 'grommet';
import { hpe } from 'grommet-theme-hpe';
// Wrap the Planner from the full setup example:
<Grommet theme={hpe} themeMode="light" full="min"><Planner /></Grommet>

代码参考

  • 上方参考表描述的是基础主题,而非此可选覆盖主题。

对象 Select 值

存储资源池 ID,同时显示其标签。

jsx
<Select options={[{id:'prod',label:'Production'},{id:'dev',label:'Development'}]}
 labelKey="label" valueKey={{key:'id',reduce:true}}
 value={poolId} onChange={({value})=>setPoolId(value)} />

代码参考

  • 在调用组件中使用 useState 声明 poolId/setPoolId。
  • 启用 reduce 后,存储的值是 ID,而不是对象。
04

HPE Grommet 设计系统 Agent 设置

实现起点

适用于包含根元素的项目的客户端 main.jsx。使用基础 Grommet,并明确声明应用字体和品牌覆盖样式。不默认启用 HPE 主题。API 已根据官方文档核对;此处尚未验证原生编译。

jsx
// npm install react react-dom grommet styled-components
import React, { useContext, useState } from 'react';
import { createRoot } from 'react-dom/client';
import { Grommet, Box, Heading, Text, Form, FormField, TextInput,
 Select, RangeInput, Meter, Button, ResponsiveContext } from 'grommet';
const theme={global:{font:{family:'Arial, sans-serif',size:'18px',height:'24px'},colors:{brand:'#7D4CDB',focus:'#6FFFB0'}}};
function Planner(){
 const size=useContext(ResponsiveContext);
 const [value,setValue]=useState({name:'',pool:'Production'});
 const [units,setUnits]=useState(20),[plan,setPlan]=useState(null);
 const used=35+units;
 return <Box pad="medium" gap="medium" width={{max:'large'}} margin="auto">
 <Heading level={1} margin="none">Plan a reservation</Heading>
 <Text>Local capacity model. No infrastructure is provisioned.</Text>
 <Box direction={size==='small'?'column':'row'} gap="large">
 <Box flex><Form value={value} onChange={setValue} validate="submit" onSubmit={({value:accepted})=>setPlan({...accepted,units})}>
 <FormField name="name" htmlFor="reservation-name" label="Reservation name" required validate={name=>String(name || '').trim().length<3?'Use at least three characters':undefined}>
 <TextInput name="name" id="reservation-name"/></FormField>
 <FormField name="pool" htmlFor="pool" label="Capacity pool"><Select name="pool" id="pool" options={['Production','Development']}/></FormField>
 <Box gap="small" margin={{vertical:'medium'}}><label htmlFor="units">Requested allocation: {units} units</label>
 <RangeInput id="units" min={5} max={60} step={5} value={units} onChange={event=>setUnits(Number(event.target.value))}/></Box>
 <Button type="submit" primary label="Prepare plan"/>
 </Form></Box>
 <Box align="center" gap="small" pad="medium" background="light-2" round="small">
 <Meter type="circle" value={used} max={100} size="small" thickness="small" color="brand" a11yTitle={`${used} of 100 units projected usage`}/>
 <Text weight="bold">{used} / 100 units used</Text><Text>{100-used} units remaining</Text>
 </Box></Box>
 {plan&&<Box background="light-2" pad="medium" role="status"><Text>Local plan: {plan.name} · {plan.pool} · {plan.units} units</Text></Box>}
 </Box>
}
createRoot(document.getElementById('root')).render(<Grommet theme={theme} themeMode="light" full="min"><Planner/></Grommet>);

适用于你项目的提示词

Agent 提示词
使用受控 Form、命名的 FormField、Select、RangeInput 和显式 max 的 Meter,实现提供的基础 Grommet 预留规划器。区分基础主题与 grommet-theme-hpe 的取值。将滑块值转换为数字,显示单位,验证名称,并且只生成本地方案快照。
05

HPE Grommet 设计系统:来源与适用范围

独立的基础 Grommet 实现参考。HPE 品牌主题的采用方式单独展示。容量数值是虚构的本地数据,并非基础设施指标,也不会触发资源配置。