@godxjp/ui 33.7.1 → 33.8.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@godxjp/ui",
3
- "version": "33.7.1",
4
- "godxUiMcp": "33.7.1",
3
+ "version": "33.8.0",
4
+ "godxUiMcp": "33.8.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -30,6 +30,7 @@
30
30
  "LICENSE",
31
31
  "DESIGN.md",
32
32
  "agent",
33
+ "skills",
33
34
  "dist",
34
35
  "scripts/ui-audit.mjs",
35
36
  "scripts/prune-css.mjs",
@@ -235,7 +235,8 @@ const PALETTE =
235
235
  * Followed by U+FE0F they are asking for emoji presentation on purpose, and then they ARE emoji —
236
236
  * so that spelling is still caught.
237
237
  */
238
- const EMOJI = /\p{Extended_Pictographic}\uFE0F|(?=\p{Extended_Pictographic})\p{Emoji_Presentation}/u;
238
+ const EMOJI =
239
+ /\p{Extended_Pictographic}\uFE0F|(?=\p{Extended_Pictographic})\p{Emoji_Presentation}/u;
239
240
  /** Regional-indicator pairs = emoji flags (🇯🇵) — broken on Win/Linux; use Intl.DisplayNames. */
240
241
  const EMOJI_FLAG = /\p{Regional_Indicator}/u;
241
242
 
@@ -995,7 +996,9 @@ const RULES = [
995
996
  scope: "consumer",
996
997
  severity: "warn",
997
998
  spansElement: true,
998
- matches: (source) => densityMatches(source, ["Card"], CARD_LIMIT),
999
+ // A dashboard's tiles ARE its surfaces — the same path test kpi-row-off-dashboard uses.
1000
+ matches: (source, rel = "") =>
1001
+ /dashboard/i.test(rel) ? [] : densityMatches(source, ["Card"], CARD_LIMIT),
999
1002
  message: `${CARD_LIMIT}+ Cards in one file — a Card per section. Mark sections with a Heading and section spacing (PageContainer children, Flex gap="lg"); keep Card for a real boundary (a table surface, a selectable item).`,
1000
1003
  },
1001
1004
  {
@@ -1055,7 +1058,8 @@ const RULES = [
1055
1058
  scope: "consumer",
1056
1059
  severity: "warn",
1057
1060
  spansElement: true,
1058
- matches: (source) => densityMatches(source, ["Alert"], ALERT_LIMIT),
1061
+ // An Alert behind a condition IS a state (what the message asks Alerts to be); count the standing ones.
1062
+ matches: (source) => densityMatches(source, ["Alert"], ALERT_LIMIT, { skipConditional: true }),
1059
1063
  message: `${ALERT_LIMIT}+ Alerts in one file. An Alert is for a state that blocks or changes the task; field errors belong in FormField, results in a toast, and standing info in plain text.`,
1060
1064
  },
1061
1065
  ];
@@ -1810,9 +1814,45 @@ function* mixedButtonSizeMatches(source) {
1810
1814
  }
1811
1815
 
1812
1816
  /** One finding per file, at the `limit`-th occurrence of any tag in `tags`, naming the count. */
1813
- function* densityMatches(source, tags, limit) {
1817
+ /**
1818
+ * The JS token before a JSX element, as the expression that places it: `?` / `:` (a ternary
1819
+ * branch), `&&` / `||` (a guard), `=>` (a callback, e.g. `.map`), `return`, or "" when the element
1820
+ * is a plain JSX child. An opening `(` is skipped — `cond ? (\n <Alert` reads as `?`.
1821
+ */
1822
+ function placementBefore(source, index) {
1823
+ let i = index - 1;
1824
+ while (i >= 0 && (/\s/.test(source[i]) || source[i] === "(")) i -= 1;
1825
+ if (source[i] === "?" || source[i] === ":") return source[i];
1826
+ if (source.slice(i - 1, i + 1) === "&&" || source.slice(i - 1, i + 1) === "||") return "&&";
1827
+ if (source.slice(i - 1, i + 1) === "=>") return "=>";
1828
+ if (/\breturn$/.test(source.slice(Math.max(0, i - 5), i + 1))) return "return";
1829
+ return "";
1830
+ }
1831
+
1832
+ /**
1833
+ * ≥limit elements of `tags` that can be on screen TOGETHER. Mutually exclusive branches of one state
1834
+ * count once: the else branch of a ternary (`a ? <X/> : <X/>`) is the same slot as its `?` branch,
1835
+ * and a function that returns the element from several `if`s returns ONE of them — gino-cloud's
1836
+ * 実習生詳細 had 6 Badge tags and showed at most 3. `skipConditional` drops elements behind a
1837
+ * condition altogether (a guard, a ternary, a `.map`).
1838
+ */
1839
+ function* densityMatches(source, tags, limit, { skipConditional = false } = {}) {
1814
1840
  const hits = [];
1815
- for (const { tag, index } of jsxElements(source)) if (tags.includes(tag)) hits.push(index);
1841
+ const returnedIn = new Set(); // function starts that already returned one of `tags`
1842
+ for (const { tag, index } of jsxElements(source)) {
1843
+ if (!tags.includes(tag)) continue;
1844
+ const how = placementBefore(source, index);
1845
+ if (skipConditional && (how === "?" || how === ":" || how === "&&" || how === "=>")) continue;
1846
+ if (how === ":") continue;
1847
+ if (how === "return" || how === "?") {
1848
+ const head = source.slice(0, index);
1849
+ const arrows = [...head.matchAll(/=>\s*\{/g)];
1850
+ const fn = Math.max(head.lastIndexOf("function "), arrows.at(-1)?.index ?? -1);
1851
+ if (returnedIn.has(fn)) continue;
1852
+ returnedIn.add(fn);
1853
+ }
1854
+ hits.push(index);
1855
+ }
1816
1856
  if (hits.length >= limit) yield { 0: `${hits.length} in this file`, index: hits[limit - 1] };
1817
1857
  }
1818
1858
 
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: godxjp-ui-design
3
+ description: Design do/don't rules for @godxjp/ui interfaces, learned from real review feedback. Use when designing, redesigning, or reviewing any web UI built with @godxjp/ui — pages, app shells, topbars, status chips. Grows as reviewers flag issues.
4
+ ---
5
+
6
+ # @godxjp/ui — Design Do / Don't
7
+
8
+ Concrete rules for interfaces built with `@godxjp/ui`, accumulated from actual reviewer feedback —
9
+ treat each as a hard rule. Combine them with the `@godxjp/ui` MCP authority (`search_components`,
10
+ `get_component`, `list_anti_ai_tells`, `list_redesign_checks`) and industry patterns for the
11
+ surface being designed.
12
+
13
+ Sibling skills: `godxjp-ui-form` (forms and inputs), `godxjp-ui-navigation`.
14
+
15
+ ## DO
16
+
17
+ - **Status chips / labels never wrap to a second line.** A `Badge` must stay on ONE line — icon +
18
+ text inline, never the icon stacked above the text. Pass a leading icon through the Badge `icon`
19
+ prop as a *component reference* (`icon={BadgeCheck}`), NEVER as an inline child
20
+ (`<Badge><BadgeCheck/> 確認済み</Badge>` column-stacks and wraps). This is `@godxjp/ui` cardinal
21
+ rule #35 ("Status chips never wrap"). It applies to every verified/pending/active-style chip on
22
+ every surface.
23
+
24
+ ## DON'T
25
+
26
+ - **Don't give a sticky top bar a semi-transparent background + `backdrop-filter`.** A
27
+ `position: sticky` topbar with `background: hsl(var(--background) / 0.96)` +
28
+ `backdrop-filter: blur/saturate` samples and tints from whatever renders behind it — colourful
29
+ content scrolling underneath, or the browser's red automation/debug banner — so the bar picks up
30
+ a stray pink/red wash. Use a FULLY OPAQUE background (`hsl(var(--background))`, no alpha, no
31
+ `backdrop-filter`) so the bar is always clean whatever is behind it.
32
+
33
+ - **Don't strip the signed-in user's profile (avatar + name) from the global topbar / header.** It
34
+ is the orientation anchor — the user must always see *who they are signed in as* in the top
35
+ right, even when the page body already has its own identity hero. Leaving only a locale switcher
36
+ + "Sign out" makes the topbar look empty or broken. Keep the profile chip (avatar + name) in the
37
+ `Topbar` `end` slot; the page hero is additive, not a replacement.
@@ -0,0 +1,82 @@
1
+ ---
2
+ name: godxjp-ui-form
3
+ description: Rules for building forms with @godxjp/ui. Use when creating or changing any form, create/edit screen, or labelled input in an app that installs the @godxjp/ui npm package. Covers page-not-modal, mandatory Form + FormField, content-sized input widths (GOV.UK Design System), and the escape hatch (open an issue on the library instead of hand-rolling). Not for apps that vendored their own copy of the components and have their own form rules.
4
+ ---
5
+
6
+ # Form rules (@godxjp/ui)
7
+
8
+ > Applies only to apps that install the `@godxjp/ui` npm package. **Out of scope:** apps that
9
+ > vendored their own copy of the components into their source tree — they have no MCP server and
10
+ > no `node_modules/@godxjp/ui`, and follow their own form and input-width rules.
11
+
12
+ Seven rules, each distilled from defects MEASURED in a production app and approved one by one by
13
+ its owner. A violation is a bug, not a style preference.
14
+
15
+ Sibling skills: `godxjp-ui-design` (visual do/don't rules), `godxjp-ui-navigation`.
16
+
17
+ ## 1. A form with 3 or more fields is its own PAGE, not a modal
18
+
19
+ Give it its own route (for example a TanStack file route with a trailing `_` so it does not nest:
20
+ `accounts_.new.tsx`; in an Inertia app, a shell route `Inertia::render('<page>')` that passes NO
21
+ data, with the page fetching from the API itself).
22
+ A `Sheet`/drawer is also an overlay and does NOT replace a page — even though `dialog-form-too-big`
23
+ does not catch a `Sheet`.
24
+ Inlining a create form as a `Card` **above the list** is also forbidden (one app had seven screens
25
+ rejected for it). The "Create" button in the page header `extra` leads to a `…/new` route; after
26
+ saving, return to the detail page or the list.
27
+ A `Dialog` is ONLY for: confirmations (delete…), very short 1–2 field forms (editing a signature),
28
+ and quick pickers. As the owner put it: "I really hate opening things in a modal — a page with a
29
+ lot of content must be created as its own page."
30
+
31
+ ## 2. ALWAYS wrap in `<Form>` — no orphan FormField, no bare control
32
+
33
+ ```tsx
34
+ <Form layout="horizontal" labelWidth="11rem" controlWidth="28rem" asChild>
35
+ <Flex direction="col" gap="md">
36
+ <FormField id="…" label={…} required>…</FormField>
37
+ </Flex>
38
+ </Form>
39
+ ```
40
+ - Desktop default is `layout="horizontal"` (label on the left — the antd convention); the kit
41
+ collapses to vertical below a breakpoint on its own (`collapseBelow`). Do NOT write your own
42
+ media query.
43
+ - Use `asChild` when the form element is owned by another library, or when submitting through a
44
+ button `onClick`.
45
+ - `required` on `FormField` adds the `*` itself — do not draw your own.
46
+
47
+ ## 3. Size inputs to their CONTENT (GOV.UK Design System)
48
+
49
+ "Make text inputs the right size for the content they're intended for" —
50
+ https://design-system.service.gov.uk/components/text-input/
51
+ - Cap for the whole form: `controlWidth="28rem"` on `<Form>` (about 45 Latin characters).
52
+ - Override per field (`controlWidth` on `FormField`) when the length is KNOWN: a port `7rem`, an
53
+ enum of 2–3 options `10rem`, a short name / preset `14rem`, a textarea for a Japanese letter
54
+ `36rem`.
55
+ - Never let a 2-option select stretch to full width — the owner caught this one by hand.
56
+
57
+ ## 4. Do NOT lay out fields yourself
58
+
59
+ Do not wrap `FormField`s in a hand-rolled horizontal `Flex` row (labels misalign at the top — a
60
+ measured bug). To weld several controls into ONE row under ONE label, use `<Flex attached>` (the
61
+ former `SpaceCompact`) inside a single `FormField`, with each control keeping its own
62
+ `aria-label`. For a grid of fields, use `<Form columns={2}>` (a `ResponsiveGrid`), not your own grid.
63
+
64
+ ## 5. Discovery before writing JSX
65
+
66
+ Call `search_components` (MCP) or read `node_modules/@godxjp/ui/docs/` FIRST.
67
+ Neighbouring code is not the standard — it may be a bug nobody has caught yet.
68
+
69
+ ## 6. Gates after writing
70
+
71
+ `node node_modules/@godxjp/ui/scripts/ui-audit.mjs <files>` must report 0 errors, together with
72
+ the repository's own type-check, tests and build. The audit enforces these rules through
73
+ `bare-control-needs-formfield`, `formfield-needs-form`, `dialog-form-too-big` and
74
+ `select-width-hint`; when the kit ships further rules, the audit takes over more of this list.
75
+
76
+ ## 7. Escape hatch = OPEN AN ISSUE, do not hand-roll
77
+
78
+ When `Form` / `FormField` / `<Flex attached>` cannot cover a case (a layout the kit does not
79
+ support, a missing prop, an audit rule that blocks wrongly), do NOT hand-roll a workaround. Open an
80
+ issue on the @godxjp/ui repository (`godx-jp/godxjp-ui`) describing the use case and the proposed
81
+ API, then either wait or use the closest kit-valid approach with a `// TODO(godxjp-ui#<n>)`
82
+ comment. Fix it upstream, not at the call site.
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: godxjp-ui-navigation
3
+ description: Navigation design rules (sidebar menu, per-role landing page, phone bottom bar, links between pages, breadcrumbs, in-page tabs) for multi-role business apps built with @godxjp/ui. Use BEFORE adding or changing a menu item, adding a page, or changing a role's landing page, and whenever navigation is criticised as confusing ("I can't tell what anything in this menu is for"). Covers the procedure (tasks → menu tree → walkthrough → measure), 28 sourced rules (NN/g, Material 3, Apple HIG, GOV.UK, SAP Fiori, Shopify Polaris and others) and an illustrative pattern for inspection and compliance apps.
4
+ ---
5
+
6
+ # Navigation for multi-role business apps (@godxjp/ui)
7
+
8
+ One question: **for a person in this role, doing this task, where does the first click go — and are
9
+ they sure it is right?** A menu is not a database diagram. A menu is each role's list of *tasks*,
10
+ ordered by frequency.
11
+
12
+ Distilled from measured failures in a real multi-role app: 17 menu items grouped by data type
13
+ ("Records / Standards / Supplies / Master data"), three overlapping entries for one task ("Log an
14
+ inspection / Inspections / Checklists"), a Settings area that was a dead end, every role seeing every
15
+ item, and a phone layout with nothing but a drawer. The owner's verdict: *"I can't tell what anything
16
+ in this menu is for."* Full sources: [references/principles.md](references/principles.md) (28 rules,
17
+ with the URL behind each one). An app may keep its own industry benchmark notes (competitor
18
+ comparisons, domain vocabulary) in its own repository; they do not belong in this package.
19
+
20
+ ## 1. Procedure — the order is the rule
21
+
22
+ 1. **Tasks first, screens second.** For each role (e.g. frontline staff, branch manager, head-office
23
+ reviewer), list their 5–10 *most frequent tasks* in their own words ("log this morning's opening
24
+ checklist", "is this batch still within its expiry date", "which branches are late on their
25
+ checklists"). Sort by frequency. This is the only input to the menu.
26
+ 2. **Split into 3 zones: Do · Set up · Review.** Daily work goes at the top; setup (templates,
27
+ recipes, configuration) goes in its own group or at the end; settings/admin go at the bottom.
28
+ 3. **Write the menu tree as text for each role** (level 1 → level 2 → page). For each item: label,
29
+ destination page, which roles see it.
30
+ 4. **Walk through the tree (no users needed)** — 8–10 tasks per role, written WITHOUT the words used
31
+ in the menu. At each level answer the 4 cognitive-walkthrough questions: will the user try to do
32
+ the right thing · will they *notice* the right item · does the label *match* their goal · after
33
+ clicking, can they tell they arrived. Record the expected first click and any **competing label**
34
+ (two labels pulling at the same task = a defect). Critical tasks must be "certainly right" on the
35
+ first click.
36
+ 5. **Measure on the real app after building it** (a manual or agent-driven test pass): inventory
37
+ every page → its entries and exits, which menu item is highlighted, dead ends, orphan pages. If
38
+ you have users, run a tree test: critical tasks need >90% success.
39
+ 6. Changing the menu structure is a **redesign** → bring a proposal (tree per role + old → new table +
40
+ walkthrough results) to the project owner for approval before writing code.
41
+
42
+ ## 2. Hard rules
43
+
44
+ **Count and form**
45
+ - Phone: **bottom bar with 3–5 items** (the middle one may be a + quick-log button); everything else
46
+ goes under "More". Never put setup on the bottom bar. Desktop: **an always-visible sidebar**, not
47
+ only a ☰ button. Choose by window width, not by device. (@godxjp/ui's `MobileShell` has a bottom
48
+ bar — use it; don't rely on a drawer alone.)
49
+ - Sidebar at most **2 levels**, groups with short headings; each role sees **≤ ~7 primary items**.
50
+ Anything deeper → list → detail inside the page.
51
+
52
+ **Grouping and labels**
53
+ - Group by **task / work area**. Never group by data table, org chart or developer vocabulary
54
+ ("Master data", generic "Records").
55
+ - A label is a short noun of 1–3 words, **in the words users say**, always with text (an icon only
56
+ supports it). The page title (H1 and `<title>`) **matches** the menu label. One concept = one name
57
+ everywhere, in every language (check every locale: e.g. not five strings sharing the root "記録"
58
+ split across two groups).
59
+ - **Each destination appears once** in the menu. Two items leading to the same kind of record = a
60
+ defect.
61
+ - Action buttons (Log/Create) are **not menu items**: one prominent primary button (top of the menu,
62
+ or the + in the middle of the bottom bar) for the #1 task; child objects are created right inside
63
+ their parent's page.
64
+
65
+ **Per role**
66
+ - Each role has its **own fixed landing page**: frontline staff → "Today" (due, overdue, my tasks);
67
+ managers/head office → "Overview" (completion rate, exceptions by branch).
68
+ - **Hide** items a role will never use (filter the menu by the current user's permissions); **dim it
69
+ and say why** when it is only temporarily blocked. The menu never changes with data state.
70
+ - Branch scope is a single control (All / Group / Branch); a person who belongs to only one branch
71
+ doesn't see it. Standards authored by head office carry a "From head office" label.
72
+
73
+ **Between pages**
74
+ - Lists are for finding; a detail page is for one object (top: key facts + actions; below: sections or
75
+ tabs). Scanning a code opens the detail page directly.
76
+ - **No dead ends:** a detail page lists its related objects with a **count**, a few preview rows, a
77
+ pre-filtered "View all" and an in-place "Create" — **both directions** (inspection → batch, and
78
+ batch → its inspections).
79
+ - From a dashboard or notification, link **straight to the record**, or to a list that is *already
80
+ filtered correctly* — never to an unfiltered list.
81
+ - Breadcrumbs show **hierarchy** (not history), from level 3 down; every crumb is a real page; the last
82
+ crumb is the parent when the H1 already names the object; use the record's **real name**, not
83
+ "Batch"/"Item". The breadcrumb and the highlighted menu item must name **the same parent**.
84
+ - In-page tabs: 1–2 words, the most-used tab first, with a count; tab state + filters + scope live **in
85
+ the URL**; Back restores scroll position, page and filters. "All" sits in the same place on every
86
+ page.
87
+ - Deep links rebuild the normal parent path (Back goes to the parent list). Every child page has a
88
+ highlighted menu item — no page leaves the menu "with the lights off".
89
+
90
+ ## 3. Illustrative pattern: inspection and compliance operations
91
+
92
+ An example only, for apps that run recurring checks across many sites:
93
+
94
+ - **Do / Set up / Review** are kept apart; templates are authored on desktop only.
95
+ - Typical set: Home · Inspections (records) · Templates · Schedule · **Actions** · Incidents · Assets ·
96
+ Analytics · (Branches/Users in organization settings).
97
+ - A failed item is handled right **inside the flow** (a required step; 3 or more fields means a page or
98
+ step, not a popup) → an "Open nonconformity" button right under the item; nonconformities/actions
99
+ stay **permanently linked** to their source record.
100
+ - Staff land on "Today" plus a separate place for "Overdue/Missed"; managers land on a rate table plus
101
+ exceptions.
102
+ - Phone bottom bar: 4–5 task items (e.g. Today · Inspections · +Log · Nonconformities · More).
103
+ - Vocabulary: avoid "Reports"/"レポート" as the label for *records* (in English "Reports" means
104
+ analytics; in Japanese "レポート" often means an individual record).
105
+
106
+ ## 4. Self-check gate (before asking for approval / before merging)
107
+
108
+ - [ ] A task table per role and a text menu tree per role exist; each role ≤ ~7 primary items; phone
109
+ 3–5 items.
110
+ - [ ] Walkthrough of 8–10 tasks per role: no step answered "no"; no pair of competing labels.
111
+ - [ ] No duplicate destinations; no grouping by data table; label = H1 = `<title>`, consistent across
112
+ every locale.
113
+ - [ ] Menu filtered by permission; landing page per role; bottom bar present on phones.
114
+ - [ ] Page inventory: 0 dead ends, 0 orphan pages, every child page has a highlighted menu item that
115
+ matches its breadcrumb.
116
+ - [ ] Every detail page links both ways to related objects, with counts and a pre-filtered "View all".
117
+ - [ ] Tabs/filters/scope live in the URL; Back keeps the position.
118
+ - [ ] Structural change → the project owner has approved the proposal.
119
+
120
+ When @godxjp/ui can't do something you need (bottom bar, menu filtering, scope switcher), open an issue
121
+ on the @godxjp/ui repository with the use case instead of hand-rolling it (the same rule as the
122
+ `godxjp-ui-form` skill).