@geomak/ui 7.18.5 → 7.20.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.
Files changed (42) hide show
  1. package/.claude/commands/ui-auth-shell.md +48 -0
  2. package/.claude/commands/ui-bootstrap.md +36 -0
  3. package/.claude/commands/ui-find.md +12 -0
  4. package/.claude/commands/ui-form.md +38 -0
  5. package/.claude/commands/ui-lookup.md +13 -0
  6. package/.claude/commands/ui-modal.md +50 -0
  7. package/.claude/commands/ui-page.md +36 -0
  8. package/.claude/commands/ui-scaffold.md +73 -0
  9. package/.claude/commands/ui-story.md +30 -0
  10. package/.claude/commands/ui-table.md +38 -0
  11. package/.claude/skills/oxygen-ui/SKILL.md +402 -0
  12. package/README.md +74 -34
  13. package/dist/{chunk-4V4U2W7K.cjs → chunk-4WD27VQX.cjs} +2 -2
  14. package/dist/chunk-4WD27VQX.cjs.map +1 -0
  15. package/dist/{chunk-KAFJJO5O.js → chunk-ILDMP2Q2.js} +2 -2
  16. package/dist/chunk-ILDMP2Q2.js.map +1 -0
  17. package/dist/{chunk-CNUDNGJM.cjs → chunk-LY3MZYWU.cjs} +3 -3
  18. package/dist/chunk-LY3MZYWU.cjs.map +1 -0
  19. package/dist/{chunk-DXOWXLKK.js → chunk-VM2725HH.js} +3 -3
  20. package/dist/chunk-VM2725HH.js.map +1 -0
  21. package/dist/icons/index.cjs +105 -105
  22. package/dist/icons/index.d.cts +2 -2
  23. package/dist/icons/index.d.ts +2 -2
  24. package/dist/icons/index.js +1 -1
  25. package/dist/{index-BktppxXp.d.ts → index-B8P5qbWt.d.cts} +5 -5
  26. package/dist/{index-BktppxXp.d.cts → index-B8P5qbWt.d.ts} +5 -5
  27. package/dist/index.cjs +29 -29
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +237 -237
  30. package/dist/index.d.ts +237 -237
  31. package/dist/index.js +18 -18
  32. package/dist/index.js.map +1 -1
  33. package/dist/tokens/index.cjs +4 -4
  34. package/dist/tokens/index.d.cts +1 -1
  35. package/dist/tokens/index.d.ts +1 -1
  36. package/dist/tokens/index.js +1 -1
  37. package/package.json +10 -3
  38. package/scripts/setup-claude.mjs +136 -0
  39. package/dist/chunk-4V4U2W7K.cjs.map +0 -1
  40. package/dist/chunk-CNUDNGJM.cjs.map +0 -1
  41. package/dist/chunk-DXOWXLKK.js.map +0 -1
  42. package/dist/chunk-KAFJJO5O.js.map +0 -1
@@ -0,0 +1,48 @@
1
+ ---
2
+ description: Generate a complete authenticated app shell with SecureLayout, sidebar, routing, and optional Wizard tour
3
+ ---
4
+
5
+ Generate an authenticated app shell for: **$ARGUMENTS**
6
+
7
+ Parse the argument as `[AppName] [route1,route2,...]`. Examples:
8
+ ```
9
+ VesOPS dashboard,vessels,settings,reports
10
+ MyApp dashboard,users
11
+ ```
12
+
13
+ AppName defaults to `App`. Routes default to `dashboard,settings`.
14
+
15
+ ## What this generates
16
+
17
+ A single `AppRoutes.tsx` file (or updates an existing one) with:
18
+
19
+ - `AppShell` with `TopBar` (brand + `ThemeSwitch`) and `sidebarSections`
20
+ - `SecureLayout` parent route guarding all provided routes
21
+ - Lazy-loaded placeholder pages for each route
22
+ - `useRef` arrays + icon wrapper spans for a `Wizard` onboarding tour
23
+ - A `Wizard` wrapping `AppShell` with `storageKey` based on the app name
24
+
25
+ ## Steps
26
+
27
+ 1. **Fetch the bootstrap code**: Call `get_app_bootstrap` with `router: true`
28
+ and the app name to get the reference implementation.
29
+
30
+ 2. **Call `get_component` for `secure-layout`** to confirm current prop names
31
+ (isAuthenticated, fallback, loadingFallback).
32
+
33
+ 3. **Generate `AppRoutes.tsx`** with:
34
+ - One `useRef<HTMLSpanElement>` per route for the Wizard tour
35
+ - `sidebarSections` array with one item per route; icon is a `<span ref={...}>` wrapping
36
+ an appropriate `<Icon.*>` (pick the most relevant icon per route name)
37
+ - `wizardSteps` array with title + description for each route
38
+ - `SecureLayout` wrapping all provided routes as child routes
39
+ - Each route uses `lazy(() => import('../pages/RouteNamePage'))` with a `Suspense` fallback
40
+ - `Wizard` wrapping `AppShell` with `steps={wizardSteps}` and `storageKey="{appName}-tour"`
41
+
42
+ 4. **Generate stub page files** for each route under `src/pages/` (e.g. `DashboardPage.tsx`)
43
+ if they do not already exist. Each stub is a minimal component with a heading.
44
+
45
+ 5. **Report** what was created and list:
46
+ - Which icons were guessed (developer may want to swap them)
47
+ - How to wire real authentication (what to replace the placeholder check with)
48
+ - How to add a route: duplicate an entry in `sidebarSections`, add a `useRef`, add a `wizardStep`, add a `<Route>`
@@ -0,0 +1,36 @@
1
+ ---
2
+ description: Generate the full app bootstrap for a new project using OxygenUI
3
+ ---
4
+
5
+ Bootstrap a new app using OxygenUI: **$ARGUMENTS**
6
+
7
+ Parse the argument as an optional app name (e.g. `MyApp`, `VesOPS`). Defaults to `App`.
8
+
9
+ ## What this generates
10
+
11
+ Four files that give a new project a working, production-ready shell:
12
+
13
+ | File | Purpose |
14
+ |---|---|
15
+ | `src/main.tsx` | Entry point, mounts Bootstrap into the DOM |
16
+ | `src/Bootstrap.tsx` | Full provider stack in the correct nesting order |
17
+ | `src/approutes/AppRoutes.tsx` | AppShell + SecureLayout + lazy routes skeleton |
18
+ | `src/utils/brandTokens.ts` | Token override object for custom branding |
19
+
20
+ ## Steps
21
+
22
+ 1. **Fetch the bootstrap code**: Call the `oxygen-ui` MCP tool `get_app_bootstrap`
23
+ with `router: true`, `reactQuery: true`, `customTheme: true`, and the app name.
24
+
25
+ 2. **Check what exists**: Before writing, check if any of the four target files
26
+ already exist. If they do, report the conflict and ask the user how to proceed
27
+ rather than overwriting.
28
+
29
+ 3. **Write the four files** with the content from the tool, substituting the app name
30
+ throughout (component names, display strings, localStorage keys).
31
+
32
+ 4. **Report** what was created and list the next steps:
33
+ - Add real routes to `AppRoutes.tsx`
34
+ - Wire real authentication (replace the `localStorage.getItem('token')` check)
35
+ - Populate `BRAND_TOKENS` if custom branding is needed
36
+ - Run `yarn add @tanstack/react-query react-router-dom` if not already installed
@@ -0,0 +1,12 @@
1
+ ---
2
+ description: Search OxygenUI for components matching a description or use-case
3
+ ---
4
+
5
+ Search OxygenUI for components that match: **$ARGUMENTS**
6
+
7
+ 1. Call the `oxygen-ui` MCP tool `find_component` with the argument as the query.
8
+ 2. Present the results as a concise table: **Name** · slug · category · description.
9
+ 3. For the top 1-2 results, briefly describe why they match and what the user
10
+ should look for in the docs (e.g. key props, integration patterns).
11
+ 4. If the search finds nothing, suggest alternative queries and offer to call
12
+ `list_components` to browse all available entries.
@@ -0,0 +1,38 @@
1
+ ---
2
+ description: Generate a fully-wired OxygenUI Form from a field specification
3
+ ---
4
+
5
+ Generate a wired OxygenUI form for: **$ARGUMENTS**
6
+
7
+ Parse the argument as a space-separated list of `field-name:input-type` pairs.
8
+ Append `?` to mark a field as optional (no required rule). Examples:
9
+
10
+ ```
11
+ email:text name:text role:dropdown notify:switch terms:checkbox
12
+ start:date end:date priority:slider tags:tags
13
+ ```
14
+
15
+ Supported input types: `text`, `textarea`, `password`, `number`, `email`,
16
+ `dropdown`, `switch`, `checkbox`, `radio`, `slider`, `date`, `daterange`,
17
+ `time`, `tags`, `color`, `rating`, `autocomplete`, `treeselect`
18
+
19
+ ## Steps
20
+
21
+ 1. **Resolve binders**: For each field, call the `oxygen-ui` MCP tool
22
+ `get_form_binding` with the input type. This returns the correct binder
23
+ method, value type, and a paste-ready snippet.
24
+
25
+ 2. **Generate the form component**: Produce a self-contained React component:
26
+ - `useForm` with `defaultValues` typed to match each field
27
+ - One `FormField` per field with the correct binder
28
+ - Required rules on all non-optional (`?`) fields
29
+ - Email pattern rule if the type is `email`
30
+ - A submit `Button`
31
+ - `onFinish` stub with a `TODO` comment
32
+
33
+ 3. **Output inline**: Deliver the component as a code block. Do not write to a
34
+ file unless the user explicitly asks to save it.
35
+
36
+ 4. **Offer next steps**: After the form, suggest:
37
+ - Adding the form inside a Modal (`/ui-modal form-in-modal`)
38
+ - Making it part of a full page (`/ui-page crud EntityName`)
@@ -0,0 +1,13 @@
1
+ ---
2
+ description: Look up a specific OxygenUI component, full props API and usage examples
3
+ ---
4
+
5
+ Look up the OxygenUI component or hook: **$ARGUMENTS**
6
+
7
+ 1. Call the `oxygen-ui` MCP tool `get_component` with the appropriate slug.
8
+ If the slug is not obvious, call `find_component` first with the argument as
9
+ the query, then call `get_component` with the best-matching slug.
10
+ 2. Return the full documentation clearly formatted, props table, usage examples,
11
+ and any caveats or recipes that are relevant.
12
+ 3. If the component accepts children or sub-components (e.g. `Modal.Body`),
13
+ highlight the composition pattern.
@@ -0,0 +1,50 @@
1
+ ---
2
+ description: Generate the complete state + Modal setup for a named OxygenUI modal pattern
3
+ ---
4
+
5
+ Generate a Modal pattern for: **$ARGUMENTS**
6
+
7
+ Parse the argument as one of: `confirm-delete`, `form-in-modal`, `detail-view`, `alert`
8
+
9
+ ## Patterns
10
+
11
+ ### confirm-delete
12
+ State + PopConfirm-style Modal for deleting a named item. Includes:
13
+ - `open` + `target` state
14
+ - `onDelete(item)` setter
15
+ - `onConfirm` async handler with `useNotification` feedback
16
+ - Full Modal JSX with cancel/confirm buttons
17
+
18
+ ### form-in-modal
19
+ State + Modal containing a Form. Includes:
20
+ - `open` + `selected` state (null = create, item = edit)
21
+ - `openCreate` / `openEdit(item)` / `closeModal` helpers
22
+ - `useEffect` to reset the form when `open` changes
23
+ - Form with two example fields (developer fills in actual fields)
24
+ - Modal with `onOk={form.submit}` wiring
25
+
26
+ ### detail-view
27
+ Read-only Modal that displays a selected item's details. Includes:
28
+ - `open` + `item` state
29
+ - Trigger pattern
30
+ - Modal with a descriptive layout (label/value pairs using Typography)
31
+
32
+ ### alert
33
+ Simple informational Modal with a single confirm button and an optional icon.
34
+
35
+ ## Steps
36
+
37
+ 1. **Fetch component API**: Call `get_component` with slug `modal` to confirm
38
+ the current prop names (onClose vs onOpenChange may differ across versions).
39
+
40
+ 2. **Generate the pattern**: Produce the complete code block:
41
+ - State declarations (paste above the return statement)
42
+ - Helper functions
43
+ - The Modal JSX (paste into the render tree)
44
+ - Any supporting imports
45
+
46
+ 3. **Output inline** as a clearly labelled code block with sections:
47
+ `// --- STATE ---`, `// --- HANDLERS ---`, `// --- JSX ---`
48
+
49
+ 4. **Offer next steps**: Suggest wrapping the form-in-modal inside a full
50
+ CRUD page with `/ui-page crud EntityName`.
@@ -0,0 +1,36 @@
1
+ ---
2
+ description: Scaffold a complete page component using OxygenUI patterns
3
+ ---
4
+
5
+ Scaffold a complete page for: **$ARGUMENTS**
6
+
7
+ Parse the argument as `<type> [EntityName]` where type is one of:
8
+ `crud`, `dashboard`, `settings`, `detail`, `multi-step-form`
9
+
10
+ EntityName is optional (e.g. `crud Vessel`, `detail Order`, `dashboard`).
11
+
12
+ ## Steps
13
+
14
+ 1. **Look up the pattern**: Call the `oxygen-ui` MCP tool `get_pattern` with the type
15
+ and entity name. This returns the full recipe: components needed, state to declare,
16
+ wiring steps, and a complete code example.
17
+
18
+ 2. **Resolve any unfamiliar props**: If the pattern uses a component whose API you are
19
+ not certain about, call `get_component` with the slug before writing code.
20
+
21
+ 3. **Determine the output path**
22
+ - Check if `src/pages/` exists; if not, check `src/views/` or `src/screens/`
23
+ - File name: `{EntityName}Page.tsx` (e.g. `VesselsPage.tsx`, `DashboardPage.tsx`)
24
+
25
+ 4. **Write the file**: Generate the complete, self-contained page component:
26
+ - TypeScript interface for the entity (if applicable)
27
+ - All imports from `@geomak/ui`
28
+ - All state declarations
29
+ - All event handlers wired up (create, edit, delete, save, etc.)
30
+ - Full JSX tree matching the pattern
31
+ - Replace all `api.*` calls with `TODO: replace with your API call`
32
+
33
+ 5. **Report** what was created and list:
34
+ - Which `api.*` calls need to be wired to real endpoints
35
+ - Which types/interfaces need to be expanded
36
+ - Any optional enhancements (e.g. "add Drawer instead of Modal for more context")
@@ -0,0 +1,73 @@
1
+ ---
2
+ description: Scaffold a new OxygenUI component, implementation + story + MDX guide
3
+ ---
4
+
5
+ Scaffold a new OxygenUI component named: **$ARGUMENTS**
6
+
7
+ Parse the argument as `ComponentName [category]` where category is optional
8
+ (defaults to the most appropriate one based on the component name).
9
+
10
+ ## Steps
11
+
12
+ 1. **Plan**: Determine:
13
+ - Target directory: `src/components/{core|inputs|forms|layout|marketing}/`
14
+ - Story title: `"Category/ComponentName"`
15
+ - Whether the component wraps a Radix primitive or is fully custom
16
+
17
+ 2. **Check for overlap**, Call `find_component` to confirm no existing component
18
+ already covers this use case before creating anything.
19
+
20
+ 3. **Scaffold files**: Create the following three files:
21
+
22
+ ### `ComponentName.tsx`
23
+
24
+ ```tsx
25
+ import React from 'react'
26
+
27
+ export interface ComponentNameProps {
28
+ // props here
29
+ className?: string
30
+ }
31
+
32
+ export function ComponentName({ className, ...props }: ComponentNameProps) {
33
+ return (
34
+ <div className={className}>
35
+ {/* implementation */}
36
+ </div>
37
+ )
38
+ }
39
+
40
+ export default ComponentName
41
+ ```
42
+
43
+ ### `ComponentName.stories.tsx`
44
+
45
+ ```tsx
46
+ import React from 'react'
47
+ import type { Meta, StoryObj } from '@storybook/react-vite'
48
+ import ComponentName from './ComponentName'
49
+
50
+ const meta: Meta<typeof ComponentName> = {
51
+ title: 'Category/ComponentName',
52
+ component: ComponentName,
53
+ parameters: { layout: 'centered' },
54
+ tags: ['autodocs'],
55
+ }
56
+ export default meta
57
+ type Story = StoryObj<typeof ComponentName>
58
+
59
+ export const Default: Story = {
60
+ args: {},
61
+ }
62
+ ```
63
+
64
+ ### `src/docs/ComponentName.mdx`
65
+
66
+ Use the MDX guide structure with HTML tables (not GFM markdown tables).
67
+ Use the exported `th / td / td0 / tbl` style constants from Accordion.mdx as a template.
68
+
69
+ 4. **Export**, Add the new component to `src/index.ts` in the correct section
70
+ (Core components, Input components, etc.).
71
+
72
+ 5. **Report** what was created and what the developer should fill in next
73
+ (implementation logic, additional stories, tests).
@@ -0,0 +1,30 @@
1
+ ---
2
+ description: Add or improve Storybook stories for an existing OxygenUI component
3
+ ---
4
+
5
+ Add or improve Storybook stories for the OxygenUI component: **$ARGUMENTS**
6
+
7
+ ## Steps
8
+
9
+ 1. **Read the component**: Find and read:
10
+ - The component source file (`src/components/**/$ARGUMENTS.tsx` or similar)
11
+ - The existing story file if one exists
12
+ - The MDX guide if one exists in `src/docs/`
13
+
14
+ 2. **Identify gaps**: Look for:
15
+ - Props that have no story coverage
16
+ - State combinations (loading, error, empty, disabled)
17
+ - Controlled vs uncontrolled usage
18
+ - Composition patterns (compound components with sub-components)
19
+ - Responsive or theme-sensitive behaviour
20
+
21
+ 3. **Write stories** following the CSF3 format used throughout the codebase:
22
+ - `Default`: the simplest working example with sensible args
23
+ - One story per major variant or visual state
24
+ - Use `render` functions for complex compositions
25
+ - Use `play` functions only when testing interactions (focus, type, click)
26
+ - Prefer realistic content that reflects actual usage in the VesOPS portal
27
+
28
+ 4. **Verify** that story `title` matches the existing Storybook sidebar path.
29
+
30
+ 5. **Report** which stories were added and what each one demonstrates.
@@ -0,0 +1,38 @@
1
+ ---
2
+ description: Generate a typed OxygenUI Table component with columns, actions, and optional CRUD wiring
3
+ ---
4
+
5
+ Generate a typed Table for: **$ARGUMENTS**
6
+
7
+ Parse the argument as `EntityName [col:type ...]`. Column type hints are optional.
8
+ Examples:
9
+
10
+ ```
11
+ Vessel name:string flag:string dwt:number status:badge actions:menu
12
+ Order id:number customer:string total:number status:badge
13
+ User
14
+ ```
15
+
16
+ Column types: `string`, `number`, `boolean`, `badge`, `date`, `link`, `menu`
17
+ - `badge` renders a `<Badge>` with tone based on the value
18
+ - `menu` adds an actions column with Edit and Delete buttons + PopConfirm on delete
19
+ - Any unlisted type defaults to a plain text renderer
20
+
21
+ ## Steps
22
+
23
+ 1. **Fetch Table API**: Call `get_component` with slug `table` to confirm the
24
+ exact `TableColumn<T>` shape and any props that have changed.
25
+
26
+ 2. **Generate the component**: Produce:
27
+ - TypeScript interface for the entity with all specified columns
28
+ - `TableColumn<Entity>[]` array with correct renderers for typed columns
29
+ - For `badge` columns: a `<Badge>` renderer with a sensible tone map
30
+ - For `menu` columns: Edit button + PopConfirm-wrapped Delete button, wired to
31
+ `onEdit` and `onDelete` callback props
32
+ - Table component with `hasSearch`, `pagination`, and `getRowKey={r => r.id}`
33
+
34
+ 3. **Output inline** as a complete, importable component.
35
+
36
+ 4. **Offer extensions**: After the output, offer to:
37
+ - Add a create/edit Modal + Form (`/ui-modal form-in-modal` or `/ui-page crud EntityName`)
38
+ - Wrap it in a full CRUD page (`/ui-page crud EntityName`)