hisd3-ui-kit 5.0.0 → 5.2.0

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/README.md CHANGED
@@ -25,7 +25,7 @@ copy and one theme chain.
25
25
  ```tsx
26
26
  import { HISD3Provider } from "hisd3-ui-kit";
27
27
 
28
- <HISD3Provider primary="red"> {/* "red" | "orange" | "teal" | "blue" | "green" | "purple" | "#hex" */}
28
+ <HISD3Provider primary="red" mode="light"> {/* primary: "red" | "orange" | "teal" | "blue" | "green" | "purple" | "brand" | "brandBlue" | "#hex"; mode: "light" | "dark" */}
29
29
  <App />
30
30
  </HISD3Provider>
31
31
  ```
@@ -33,7 +33,7 @@ import { HISD3Provider } from "hisd3-ui-kit";
33
33
  `HISD3Provider` sets up antd's `ConfigProvider` (CSS variables on, so every kit
34
34
  component and every plain antd component follows the chosen primary), antd
35
35
  `App` (themed `modal.confirm` / `message`), and the styled-components
36
- `ThemeProvider`. Options: `primary`, `borders` (`"hairline"` default, or
36
+ `ThemeProvider`. Options: `primary`, `mode` (`"light"` default, or `"dark"`), `borders` (`"hairline"` default, or
37
37
  `"bold"` for the original 2px near-black rules), `radius` (default 0),
38
38
  `lineWidth` (overrides the `borders` preset), `overrides` (extra antd
39
39
  `ThemeConfig`), or `theme` to bypass the generator entirely.
@@ -44,7 +44,36 @@ states. Every kit component follows `--hisd3-rule-width`, so switching
44
44
  `borders="bold"` retunes the sidebar, header, table, tabs, pagination, inputs
45
45
  and buttons together.
46
46
 
47
- Need just the antd theme object (e.g. for Storybook)? `createHisd3Theme({ primary: "teal" })`.
47
+ Need just the antd theme object (e.g. for Storybook)? `createHisd3Theme({ primary: "teal", mode: "dark" })`.
48
+
49
+ ### One primary, readable in light and dark
50
+
51
+ An app sets one thing, its `primary`; neutrals, type, spacing and status
52
+ colours are the same for every app. The kit makes any primary readable:
53
+
54
+ - **Light:** a primary is darkened until it reads at 4.5:1 on the page, on
55
+ its own tint and under white text. Teal, Blue, Green and Purple are used as
56
+ given; Red, Orange, Brand and Brand blue come out a little darker.
57
+ - **Dark:** it is lightened until it reads at 4.5:1 on the dark page and on
58
+ its tint, and carries dark text (`--hisd3-on-primary`).
59
+ - `resolvePrimaryPalette(primary, mode)` returns what the kit applies
60
+ (`primary`, `onPrimary`, `primaryBg`, …; `source` is the colour as asked
61
+ for, for logos only). `contrastRatio(a, b)` is the WCAG ratio it checks with.
62
+
63
+ Status colours (`HISD3_STATUS`) replace antd's defaults, which failed
64
+ contrast: success `#2E7D32`, error `#B42318`, warning `#B54708` in light;
65
+ `#6FBF73`, `#FF8A7A`, `#F0A35E` in dark, each on its own tint. Every form
66
+ field (text, number, select, date, cascader, tree, mentions, checkbox,
67
+ radio, search) shares one 3:1 edge (`controlBorder`, `--hisd3-input-border`),
68
+ the field fill and a 2px primary edge on focus.
69
+
70
+ `mode` is the app's to own: keep the person's choice (light, dark, or the
71
+ computer's `prefers-color-scheme`) and pass the result in. Dark mode is the
72
+ same system on a warm near-black (`HISD3_NEUTRALS_DARK`); every kit
73
+ component reads CSS variables, so nothing is inverted by hand. For a region
74
+ that must stay light in a dark app (a printout), scope the light variables to
75
+ it: `hisd3VarsCss({ primary, mode: "light", selector: ".my-paper" })` plus an
76
+ antd `ConfigProvider` with `createHisd3Theme({ primary, mode: "light" })`.
48
77
 
49
78
  ## 2. Build a page
50
79
 
@@ -112,11 +141,12 @@ const menuItems = [
112
141
  | `HISD3Provider` | Root theme provider (see above). |
113
142
  | `HISD3Sidebar` | App shell (see *Scrolling* below): brand block, grouped menu with accent bar on the active route, account dropdown (Settings / Logout with confirm), collapsible, optional top-nav mode (`layoutTop`). `menuItems` accept `{ key, path, name, icon, children, group, hideInMenu, disabled }`. `renderMenuLink` lets you plug in react-router's `<Link>`. Props `bareContent` + `hideHeaderBar` hand the header over to `HISD3PageHeader`. `collapseTrigger` places the collapse control: `"edge"` (default) floats a round chevron on the sidebar's right edge, level with the top bar — it works even when the top bar is hidden, and `collapseTriggerOffset` moves it down — `"header"` puts a square button in the shell's own top bar, `"none"` renders neither. |
114
143
  | `HISD3PageHeader` / `HISD3PageBody` | Top bar (breadcrumb left, actions right) that stays pinned while the page scrolls, plus a large title + subtitle that scrolls away; `HISD3PageBody` is the matching padded content area. |
115
- | `HISD3Table<T>` | antd `Table` restyled compactly — 45px rows, 14px cell text, uppercase 11px headers, hairline row rules. antd's own `size="small"` tightens it further with the HISD3 pagination bar: "Total N items", square page buttons, page-size toggle. Pass `pagination={{ current, pageSize, total, onChange, pageSizeOptions?, hidePageSize? }}` or `false`. Optional `footer` strip. Cell helper classes: `hisd3-cell-primary`, `hisd3-cell-link`, `hisd3-cell-muted`. |
144
+ | `HISD3Table<T>` | antd `Table` restyled compactly — 45px rows, 14px cell text, uppercase 12px headers in the secondary text colour, hairline row rules. antd's own `size="small"` tightens it further with the HISD3 pagination bar: "Total N items", square page buttons, page-size toggle. Pass `pagination={{ current, pageSize, total, onChange, pageSizeOptions?, hidePageSize? }}` or `false`. Optional `footer` strip. Cell helper classes: `hisd3-cell-primary`, `hisd3-cell-link`, `hisd3-cell-muted`. |
116
145
  | `HISD3Tabs` | Underlined filter tabs; each item may carry a `count`. |
117
- | `HISD3Tag` | Uppercase status pill. `variant`: `neutral` (grey, e.g. ACTIVE / IN PATIENT), `soft` (primary tint, e.g. ER PATIENT), `outline` (2px primary border, e.g. OUT PATIENT), `solid`. `tone`: `primary` \| `success` \| `warning` \| `danger` \| `default`. |
146
+ | `HISD3Tag` | Uppercase status pill, 12px on a 24px pill. `variant`: `neutral` (grey, e.g. ACTIVE / IN PATIENT), `soft` (primary tint, e.g. ER PATIENT), `outline` (2px primary border, e.g. OUT PATIENT), `solid`. `tone`: `primary` \| `success` \| `warning` \| `danger` \| `default`. |
118
147
  | `HISD3Button` | `variant`: `primary` (filled), `secondary` (default, dark 2px outline), `ghost`, `danger`. Accepts all antd `Button` props (`icon`, `size`, `loading`, …). |
119
- | `HISD3Input` / `HISD3SearchInput` | 2px-bordered input; the search variant is the grey filled hero field with a leading icon (`compact` for a 48px version). |
148
+ | `HISD3Input` / `HISD3SearchInput` | 2px-bordered input; the search variant is a light field with a leading icon and a visible border, lighter than the page so it never reads as disabled. `size`: `"small"` 32px, `"middle"` 40px (default), `"large"` 56px. Colours: `--hisd3-input-bg`, `--hisd3-input-bg-hover`, `--hisd3-input-border-hover`. |
149
+ | `HISD3Select` | antd `Select` that wraps long text instead of cutting it with "…", and shows an option's `description` on a second line. See [Select](#select). |
120
150
  | `HISD3Form*` fields | Every antd data-entry control pre-wrapped in `Form.Item`, with `loading` skeletons. See *Form fields* below. |
121
151
  | `HISD3HeaderActions` | Spacing wrapper for the top-right controls; `divided` inserts a rule before the last child. |
122
152
  | `HISD3NotificationButton` | Soft-grey circular button with a solid bell glyph and a count pill on its top-right edge; tints to the primary color while its panel is open. Pass `icon` to swap the glyph. Props: `items` (`{ id, title, description, time, unread, avatarSrc, icon, onClick }`), `count` (defaults to the unread tally), `loading`, `size` (default 40), `icon`, `onMarkAllRead`, `onSeeAll`, `emptyText`. |
@@ -125,7 +155,9 @@ const menuItems = [
125
155
  | `UserMenu` | The sidebar-footer account card, on its own. |
126
156
 
127
157
  Theme utilities: `createHisd3Theme`, `hisd3AntdTheme` (red default),
128
- `HISD3_PRESETS`, `HISD3_NEUTRALS`, `HISD3_BORDER_PRESETS`, `borderVarsCss`,
158
+ `HISD3_PRESETS`, `HISD3_NEUTRALS`, `HISD3_NEUTRALS_DARK`, `HISD3_STATUS`,
159
+ `HISD3_BORDER_PRESETS`, `HISD3_BORDER_PRESETS_DARK`, `hisd3VarsCss`,
160
+ `resolvePrimaryPalette`, `contrastRatio`, `mix`, `shade`, `borderVarsCss`,
129
161
  `HISD3_FONT_FAMILY`,
130
162
  `HISD3_FONT_WEIGHT_HEADING` (800) / `HISD3_FONT_WEIGHT_BODY` (400), `HISD3_LAYOUT`,
131
163
  `resolvePrimary`, `tint`. Plain antd components (Form, Select, DatePicker,
@@ -161,7 +193,10 @@ Inside styled-components or CSS you can rely on antd's variables:
161
193
  `var(--ant-color-border)`, `var(--ant-color-border-secondary)`,
162
194
  `var(--ant-color-text)`, `var(--ant-color-text-tertiary)`,
163
195
  `var(--ant-color-bg-layout)`. The header controls additionally read
164
- `--hisd3-control-bg` / `--hisd3-control-bg-hover` (the grey circle fill) and
196
+ `--hisd3-control-bg` / `--hisd3-control-bg-hover` (the grey circle fill),
197
+ `--hisd3-input-border` / `--hisd3-input-border-hover` (every field's edge),
198
+ `--hisd3-on-primary` (text on a primary fill), `--hisd3-hover` (a row's hover
199
+ wash) and
165
200
  `--hisd3-popup-radius`, `--hisd3-bell-stretch` (how wide the bell glyph is drawn, default `1.12`), `--hisd3-edge-trigger-bg` / `--hisd3-edge-trigger-color` (the sidebar collapse chevron, primary-filled by default), so you can retune them per app without forking the
166
201
  components.
167
202
 
@@ -202,6 +237,42 @@ logo is used. `HISD3_LOGO_SRC` is exported if you need the mark elsewhere.
202
237
  `primary` accepts the brand presets `"brand"` (the logo's gear, `#E5533B`) and
203
238
  `"brandBlue"` (its cloud, `#1B6FE0`), any other preset, or a hex value.
204
239
 
240
+ ## Select
241
+
242
+ `HISD3Select` is antd's `Select` with two additions, and takes every `Select`
243
+ prop. `HISD3FormSelect` uses it, so both work the same way.
244
+
245
+ - **Long text wraps** — in the chosen value and in every option — instead of
246
+ being cut off with "…". On by default; `wrap={false}` turns it off.
247
+ - **`description` on an option** is shown under its label, smaller and muted,
248
+ in the dropdown and in the box. With `showSearch`, typing matches the label
249
+ and the description.
250
+
251
+ `monoLabel` puts the label line in a monospace font, for codes:
252
+
253
+ ```tsx
254
+ <HISD3Select
255
+ showSearch
256
+ monoLabel
257
+ placeholder="Search an account…"
258
+ options={accounts.map((a) => ({ value: a.code, label: a.code, description: a.title }))}
259
+ />
260
+
261
+ <HISD3FormSelect
262
+ name="accountCode"
263
+ label="Account"
264
+ fieldProps={{ showSearch: true, monoLabel: true, options: accountOptions }}
265
+ />
266
+ ```
267
+
268
+ Your own `optionRender`, `labelRender`, `filterOption` or `optionFilterProp`
269
+ replaces the default. `HISD3SelectLabel` renders the same two-line layout for a
270
+ custom `optionRender` / `labelRender`.
271
+
272
+ Wrapped rows are not all one height, so `virtual` is off while `wrap` is on.
273
+ For a list of thousands of options, pass `virtual` (or search on the server and
274
+ show a capped list). Tags in `mode="multiple"` stay on one line.
275
+
205
276
  ## Form fields
206
277
 
207
278
  Each `HISD3Form*` field is an antd control inside a `Form.Item`. It takes every
@@ -225,7 +296,7 @@ Each `HISD3Form*` field is an antd control inside a `Form.Item`. It takes every
225
296
  | `HISD3FormInputNumber` | `InputNumber` | number |
226
297
  | `HISD3FormAutoComplete` | `AutoComplete` | string |
227
298
  | `HISD3FormMentions` | `Mentions` | string |
228
- | `HISD3FormSelect` | `Select` | value / value[] |
299
+ | `HISD3FormSelect` | `HISD3Select` | value / value[] |
229
300
  | `HISD3FormTreeSelect` | `TreeSelect` | value / value[] |
230
301
  | `HISD3FormCascader` | `Cascader` | path array |
231
302
  | `HISD3FormRadioGroup` | `Radio.Group` | value |
@@ -327,6 +398,20 @@ again — and the instance unmounts once the animation finishes.
327
398
 
328
399
  ## Migrating
329
400
 
401
+ ### from 5.1
402
+
403
+ Nothing to change in code; the look moves:
404
+
405
+ - Status colours, field edges, placeholders, column headings (12px), tags
406
+ (12px on 24px), sidebar group titles (12px) and the Segmented control now
407
+ meet WCAG AA. An app that set these itself in `overrides` can drop them.
408
+ - A light primary is darkened a little in light mode (see "One primary,
409
+ readable in light and dark").
410
+ - Card titles: 18px, and 16px on `size="small"` cards.
411
+ - `HISD3Sidebar` shows the HISD3 mark when `logoUrl` fails to load, not a
412
+ broken image.
413
+ - New: `mode: "dark"`.
414
+
330
415
  ### from 3.x
331
416
 
332
417
  - Wrap the app in `HISD3Provider` (the sidebar still works standalone with the red default, but the provider is what lets you pick a primary).