@momoi-labs/kiso 0.4.1 → 0.6.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
@@ -66,7 +66,11 @@ Code, config, and templates: **MIT**. Brand assets (name, logo, type):
66
66
 
67
67
  [`@momoi-labs/kiso-react`](packages/kiso-react/README.md) provides React components
68
68
  using Kiso tokens and CSS. Run `npm ci` and `npm run prototype` to open the
69
- Self Host simulation and the full component gallery.
69
+ component gallery, where every entry renders the published component.
70
+
71
+ The [standalone Kiso gallery](apps/kiso-gallery/README.md) has its own build
72
+ and Cloudflare configuration for `kiso.momoi-labs.dev`. Run `npm run gallery`
73
+ to open it locally, or `npm run build:gallery` to produce the static site.
70
74
 
71
75
  See [Publishing Kiso](docs/publishing.md) for the first npm publication, trusted
72
76
  publisher setup, release PRs, and version tags.
@@ -1,55 +1,63 @@
1
1
  # Kiso component catalog
2
2
 
3
- Kiso defines product UI as markdown contracts rather than implementation code.
4
- Each contract specifies anatomy, states, accessibility, usage guidance, semantic
5
- token consumption, and a Radix/shadcn behavioral reference where one exists.
3
+ Kiso documents each component in a Markdown contract covering anatomy, states,
4
+ accessibility, usage, and token consumption. Contracts include a Radix/shadcn
5
+ behavioral reference where one exists.
6
6
 
7
7
  ## Nucleus
8
8
 
9
- - [Alert](alert.md) — Communicates persistent in-page information, success, warnings, or errors.
10
- - [Badge](badge.md) — Labels status or compact metadata without becoming an action.
11
- - [Button](button.md) — Triggers a visible, text-labeled action without changing the URL.
12
- - [Card](card.md) — Groups related content and actions with visual separation.
13
- - [Checkbox](checkbox.md) — Toggles an option in a list or selects multiple values.
14
- - [FormField](form-field.md) — Composes Label, a form control, HelperText, and ValidationMessage with consistent ID and ARIA wiring.
15
- - [HelperText](helper-text.md) — Provides persistent, non-error context for a form control.
16
- - [IconButton](icon-button.md) — Triggers a compact icon-only action with a required accessible name.
17
- - [Input](input.md) — Collects a single-line text-like value.
18
- - [Label](label.md) — Gives a form control its visible, programmatically associated name.
19
- - [Link](link.md) — Navigates to a URL while preserving native link behavior.
20
- - [Select](select.md) — Chooses one value from a predefined set of options.
21
- - [Skeleton](skeleton.md) — Preserves known layout while its content is loading.
22
- - [Spinner](spinner.md) — Signals indeterminate work when the final layout is not represented.
23
- - [Switch](switch.md) — Changes one immediately applied boolean setting.
24
- - [Textarea](textarea.md) — Collects multi-line free-form text.
25
- - [ThemeSelector](theme-selector.md) — Chooses between following the system colour scheme, forcing light, or forcing dark.
26
- - [Tooltip](tooltip.md) — Adds nonessential pointer or keyboard context as progressive enhancement.
27
- - [ValidationMessage](validation-message.md) — Explains a field-level validation error and how to fix it.
9
+ - [Alert](alert.md): Communicates persistent in-page information, success, warnings, or errors.
10
+ - [Badge](badge.md): Labels status or compact metadata without becoming an action.
11
+ - [Button](button.md): Triggers a visible, text-labeled action without changing the URL.
12
+ - [Card](card.md): Groups related content and actions with visual separation.
13
+ - [Checkbox](checkbox.md): Toggles an option in a list or selects multiple values.
14
+ - [FormField](form-field.md): Composes Label, a form control, HelperText, and ValidationMessage with consistent ID and ARIA wiring.
15
+ - [HelperText](helper-text.md): Provides persistent, non-error context for a form control.
16
+ - [IconButton](icon-button.md): Triggers a compact icon-only action with a required accessible name.
17
+ - [Input](input.md): Collects a single-line text-like value.
18
+ - [Label](label.md): Gives a form control its visible, programmatically associated name.
19
+ - [Link](link.md): Navigates to a URL while preserving native link behavior.
20
+ - [Select](select.md): Chooses one value from a predefined set of options.
21
+ - [Skeleton](skeleton.md): Preserves known layout while its content is loading.
22
+ - [Spinner](spinner.md): Signals indeterminate work when the final layout is not represented.
23
+ - [Switch](switch.md): Changes one immediately applied boolean setting.
24
+ - [Textarea](textarea.md): Collects multi-line free-form text.
25
+ - [ThemeSelector](theme-selector.md): Chooses between following the system colour scheme, forcing light, or forcing dark.
26
+ - [Tooltip](tooltip.md): Adds nonessential pointer or keyboard context as progressive enhancement.
27
+ - [ValidationMessage](validation-message.md): Explains a field-level validation error and how to fix it.
28
28
 
29
29
  ## Data
30
30
 
31
- - [CommandPalette](command-palette.md) — Searches and runs global actions or navigation from a keyboard-first overlay.
32
- - [DropdownMenu](dropdown-menu.md) — Presents contextual actions anchored to a specific object or trigger.
33
- - [EmptyState](empty-state.md) — Replaces an empty collection with an explanation and optional next action.
34
- - [Search](search.md) — Filters visible content such as a list or table.
35
- - [Table / DataTable](table.md) — Presents structured records with optional sorting, selection, filtering, and pagination.
31
+ - [CommandPalette](command-palette.md): Searches and runs global actions or navigation from a keyboard-first overlay.
32
+ - [Dot](dot.md): Adds a decorative status mark beside readable text.
33
+ - [DropdownMenu](dropdown-menu.md): Presents contextual actions anchored to a specific object or trigger.
34
+ - [EmptyState](empty-state.md): Replaces an empty collection with an explanation and optional next action.
35
+ - [KV](kv.md): Describes one object through named facts.
36
+ - [LogView](log-view.md): Displays scrollable log output with follow-tail behavior.
37
+ - [Search](search.md): Filters visible content such as a list or table.
38
+ - [Stat](stat.md): Presents a named metric with optional change and context.
39
+ - [Table / DataTable](table.md): Presents structured records with optional sorting, selection, filtering, and pagination.
36
40
 
37
41
  ## Navigation and structure
38
42
 
39
- - [Breadcrumb](breadcrumb.md) — Shows the current location within a hierarchy.
40
- - [Header](header.md) — Composes persistent application navigation and global actions.
41
- - [Navigation](navigation.md) — Provides a generic semantic container for destination links.
42
- - [PageHeader](page-header.md) — Composes a page title, optional subtitle, and page-scoped action Buttons.
43
- - [Pagination](pagination.md) — Moves through known pages while exposing the current position.
44
- - [Sidebar](sidebar.md) — Organizes persistent navigation into optionally collapsible sections.
45
- - [Tabs](tabs.md) — Switches among related content panels within the same page context.
43
+ - [AppShell](app-shell.md): Places Sidebar navigation beside the main application content.
44
+ - [BrandMark](brand-mark.md): Decorative letter or icon beside a product name.
45
+ - [Breadcrumb](breadcrumb.md): Shows the current location within a hierarchy.
46
+ - [Header](header.md): Composes persistent application navigation and global actions.
47
+ - [Navigation](navigation.md): Provides a generic semantic container for destination links.
48
+ - [PageHeader](page-header.md): Composes a page title, optional subtitle, and page-scoped action Buttons.
49
+ - [Pagination](pagination.md): Moves through known pages while exposing the current position.
50
+ - [Separator](separator.md): Marks a visual or semantic boundary in either orientation.
51
+ - [Sidebar](sidebar.md): Organizes persistent navigation into optionally collapsible sections.
52
+ - [Split / Pane / Splitter](split.md): Allocates width between related panes with pointer and keyboard resizing.
53
+ - [Tabs](tabs.md): Switches among related content panels within the same page context.
46
54
 
47
55
  ## Overlay
48
56
 
49
- - [Drawer](drawer.md) — Presents a viewport-adaptive panel, including a mobile alternative to Modal/Dialog.
50
- - [Modal / Dialog](modal-dialog.md) — Blocks the page for a focused task that requires attention or a decision.
51
- - [Popover](popover.md) — Shows rich, interactive contextual content anchored to a trigger.
52
- - [Toast](toast.md) — Reports transient system feedback without replacing in-page status or field errors.
57
+ - [Drawer](drawer.md): Presents a viewport-adaptive panel, including a mobile alternative to Modal/Dialog.
58
+ - [Modal / Dialog](modal-dialog.md): Blocks the page for a focused task that requires attention or a decision.
59
+ - [Popover](popover.md): Shows rich, interactive contextual content anchored to a trigger.
60
+ - [Toast](toast.md): Reports transient system feedback without replacing in-page status or field errors.
53
61
 
54
62
  ## Required compositions
55
63
 
@@ -0,0 +1,68 @@
1
+ # AppShell
2
+
3
+ ## Purpose
4
+
5
+ AppShell places persistent [Sidebar](sidebar.md) navigation beside the main
6
+ application content. It owns the page columns, not navigation state.
7
+
8
+ ## Anatomy
9
+
10
+ ```
11
+ AppShell
12
+ ├── Sidebar
13
+ └── AppShellMain
14
+ ├── Header or PageHeader (optional)
15
+ └── page content
16
+ ```
17
+
18
+ The two slots are direct children. AppShell is a `div`; AppShellMain is a
19
+ `main` with `min-width: 0`, so wide tables and log lines cannot push the
20
+ Sidebar off screen. Sidebar owns its header, body, and footer.
21
+
22
+ ## Variants
23
+
24
+ One layout. No variant prop. Compose [Header](header.md) and
25
+ [PageHeader](page-header.md) inside the main slot as the page requires.
26
+
27
+ ## Sizes
28
+
29
+ The Sidebar column uses `--size-sidebar`; the main column takes the remaining
30
+ width with a zero minimum. The shell has a minimum height of one viewport.
31
+ At widths of 1023px or less, the layout becomes one column and Sidebar is
32
+ hidden. The product must provide access to navigation at that width, for
33
+ example through a [Drawer](drawer.md).
34
+
35
+ ## States
36
+
37
+ The shell stays in place while page content loads, fails, or becomes empty.
38
+ Those states belong inside AppShellMain. There is no disabled or active shell.
39
+
40
+ ## Accessibility
41
+
42
+ - Use one main landmark for the page. Do not nest another `main` inside
43
+ AppShellMain.
44
+ - Give the Sidebar's navigation an accessible name and provide a skip link to
45
+ the main content.
46
+ - Keep navigation available when the Sidebar is hidden. AppShell does not
47
+ create a mobile menu or manage its focus.
48
+
49
+ ### Keyboard
50
+
51
+ No shell keymap. Tab follows the controls in DOM order; navigation and Drawer
52
+ retain their own keyboard behavior.
53
+
54
+ ## When to use
55
+
56
+ - An application with persistent navigation beside a changing page.
57
+ - A console containing tables, detail panes, and logs in its main column.
58
+
59
+ ## When NOT to use
60
+
61
+ - A standalone login or centered form. Use [Card](card.md) within the page.
62
+ - Two resizable content panes. Use [Split](split.md) inside the main content.
63
+
64
+ ## Radix/shadcn mapping
65
+
66
+ No dedicated Radix primitive. Compose Sidebar and a semantic main region.
67
+ AppShell supplies Kiso's column layout; it does not add a Sidebar provider,
68
+ routing, or collapse state.
@@ -0,0 +1,43 @@
1
+ # BrandMark
2
+
3
+ ## Purpose
4
+
5
+ BrandMark is the small rounded square next to a product name in a sidebar or
6
+ login header. It holds a letter or a single inline SVG. The self-host console
7
+ uses the momoi-labs terminal prompt logo, as shown in
8
+ [self-host PR #48](https://github.com/momoi-labs/self-host/pull/48).
9
+
10
+ ## Anatomy and variants
11
+
12
+ - A decorative `span` with the existing `.brand-mark` class.
13
+ - Letter content, such as "S", keeps the class's font weight and font size.
14
+ - Icon content uses `.icon.icon-sm`. The icon inherits `currentColor`, has no
15
+ fill, and uses a 1.75 stroke width with round caps and joins.
16
+ - The adjacent product name supplies the accessible name.
17
+
18
+ In React, pass either content through `children`, as with Button and Badge.
19
+ BrandMark adds the icon classes to an element child without an extra wrapper.
20
+ Custom icon components must forward `className` to their inline SVG.
21
+
22
+ `TerminalIcon` supplies the momoi-labs `>_` glyph on a 16 by 16 viewBox. Its
23
+ paths are `M4 4.5L8 8l-4 3.5` and `M9.5 11.5H13`.
24
+
25
+ ## States and accessibility
26
+
27
+ BrandMark is static and always has `aria-hidden="true"`, including when a
28
+ consumer passes a different value. Keep the product name visible beside it.
29
+ Do not put interactive or focusable content inside the mark. If the brand
30
+ navigates, wrap the mark and product name together in a Link.
31
+
32
+ ## Token consumption
33
+
34
+ The existing `.brand-mark` CSS remains unchanged. Grid placement centers the
35
+ content; `--size-control-sm` sets both dimensions and `--radius-lg` rounds the
36
+ corners. The background uses `--color-primary` and the foreground uses
37
+ `--color-primary-foreground`. Letter typography uses `--type-weight-bold` and
38
+ `--type-size-label`; icon dimensions use `--size-icon-sm`.
39
+
40
+ ## Radix/shadcn mapping
41
+
42
+ There is no dedicated behavioral primitive. The React implementation uses
43
+ Radix Slot to merge icon classes onto the child SVG.
@@ -0,0 +1,69 @@
1
+ # Dot
2
+
3
+ ## Purpose
4
+
5
+ Dot adds a small decorative status cue beside text. [Badge](badge.md) carries
6
+ a status label; Dot supplies only the colored mark. Keep readable status text
7
+ beside it, whether inside a Badge or elsewhere in the row.
8
+
9
+ ## Anatomy
10
+
11
+ A single `span`, hidden from assistive technology with `aria-hidden="true"`.
12
+ An optional pulse adds a halo behind the mark. Dot contains no label or control.
13
+
14
+ ## Variants
15
+
16
+ Status is spelled `variant`, matching Badge.
17
+
18
+ | Variant | Meaning | Color |
19
+ | --- | --- | --- |
20
+ | `neutral` (default) | No severity. | Inherits `currentColor` from its context. |
21
+ | `info` | Informational state. | `--color-info` |
22
+ | `success` | Healthy or complete. | `--color-success` |
23
+ | `warning` | Needs attention. | `--color-warning` |
24
+ | `danger` | Failed or blocked. | `--color-danger` |
25
+
26
+ `pulse` defaults to `false`. Enable it only for a live activity cue that the
27
+ adjacent text also explains. The halo uses `currentColor` and a two-second
28
+ animation with `--motion-easing-standard`.
29
+
30
+ ## Sizes
31
+
32
+ `size="md"` is the default 6px mark; `size="lg"` is 8px. Both use
33
+ `--radius-full` and do not shrink in a flex row. These are visual marks,
34
+ not pointer targets.
35
+
36
+ ## States
37
+
38
+ The mark is static unless `pulse` is enabled. A status change updates the
39
+ variant and accompanying text together. There are no hover, focus, active,
40
+ or disabled states.
41
+
42
+ ## Accessibility
43
+
44
+ - Keep Dot decorative. Do not use it as the only indication of status or
45
+ override its hidden semantics to make an icon-only status label.
46
+ - Communicate status and activity with text; color and motion are extra cues.
47
+ - Respect reduced-motion preferences by leaving `pulse` off for those users.
48
+ Dot does not detect the preference itself.
49
+ - Necessary status announcements belong to the surrounding region, not Dot.
50
+
51
+ ### Keyboard
52
+
53
+ No keymap and no tab stop. Dot is never an action.
54
+
55
+ ## When to use
56
+
57
+ - A health cue beside "Running", "Degraded", or "Stopped".
58
+ - A decorative mark inside a Badge that already names the state.
59
+
60
+ ## When NOT to use
61
+
62
+ - A status with no accompanying text. Use Badge with a label.
63
+ - Notification counts or clickable indicators.
64
+ - Indeterminate work that needs a loading indicator. Use [Spinner](spinner.md).
65
+
66
+ ## Radix/shadcn mapping
67
+
68
+ No dedicated Dot primitive. A decorative span consumes Kiso status colors;
69
+ Badge remains the reference for variant names and meanings.
@@ -0,0 +1,67 @@
1
+ # KV
2
+
3
+ ## Purpose
4
+
5
+ KV presents named facts about one object, such as its region, image, and
6
+ restart policy. A description list expresses the relationship between each
7
+ term and its value without implying tabular records.
8
+
9
+ ## Anatomy
10
+
11
+ ```
12
+ KV (dl)
13
+ ├── KVKey (dt)
14
+ ├── KVValue (dd)
15
+ └── further key/value pairs
16
+ ```
17
+
18
+ Keep keys and values as direct children, in reading order. Each key names the
19
+ fact described by the following value. Values can contain text, a
20
+ [Badge](badge.md), or a [Link](link.md).
21
+
22
+ ## Variants
23
+
24
+ One description-list layout. No variant prop.
25
+
26
+ ## Sizes
27
+
28
+ One size. The key column has a 96px minimum and grows with its content; the
29
+ value column takes remaining space with a zero minimum. Row and column gaps
30
+ use `--spacing-sm` and `--spacing-lg`. Keys use
31
+ `--color-muted-foreground` and `--type-size-label`; values use `--font-mono`
32
+ and `--type-size-label`. Long values wrap anywhere to stay within the column.
33
+
34
+ ## States
35
+
36
+ Static facts have no hover, active, or disabled state. The product supplies
37
+ loading placeholders and explicit unknown or unavailable values. Keep the
38
+ key visible when a value is missing so the reader knows which fact is absent.
39
+
40
+ ## Accessibility
41
+
42
+ Preserve native `dl`, `dt`, and `dd` semantics. Do not replace them with generic
43
+ containers or table roles just to align text. The list describes one object;
44
+ it has no column headers, row selection, or sorting. Name any controls within
45
+ a value according to their own contracts.
46
+
47
+ ### Keyboard
48
+
49
+ No list keymap or tab stop. Links and controls inside values remain in normal
50
+ tab order.
51
+
52
+ ## When to use
53
+
54
+ - Fixed facts in a resource detail pane.
55
+ - Configuration summaries that the reader scans by name.
56
+
57
+ ## When NOT to use
58
+
59
+ - Repeated records with the same fields across columns. Use [Table](table.md).
60
+ - Editable settings. Compose [FormField](form-field.md) and controls.
61
+ - One prominent metric and its trend. Use [Stat](stat.md).
62
+
63
+ ## Radix/shadcn mapping
64
+
65
+ No dedicated primitive. Use native HTML description-list semantics with Kiso's
66
+ layout and typography. A two-column shadcn Table is not a substitute for a
67
+ list of facts about one object.
@@ -0,0 +1,91 @@
1
+ # LogView
2
+
3
+ ## Purpose
4
+
5
+ LogView displays log lines in a bounded, scrollable frame and follows new
6
+ output while the reader stays at the end. It owns the scroller and follow-tail
7
+ behavior; the product owns the log source and any toolbar controls.
8
+
9
+ ## Anatomy
10
+
11
+ ```
12
+ LogView (frame)
13
+ └── internal scroller
14
+ └── LogViewLine (repeated)
15
+ ├── LogViewTime (optional)
16
+ ├── LogViewLevel (optional)
17
+ └── message
18
+ ```
19
+
20
+ Set height on LogView. Its internal scroller takes the available space and
21
+ owns overflow. Do not add a second scrolling wrapper around the lines. Root
22
+ props target the frame; the ref exposes a handle, not its DOM element.
23
+ Time and level slots accept text supplied by the product.
24
+
25
+ ## Variants
26
+
27
+ LogView has one dark log treatment. LogViewLevel uses `level`, with `info`
28
+ (default), `warn`, and `error` mapped to `--color-info-on-dark`,
29
+ `--color-warning-on-dark`, and `--color-danger-on-dark`. Include readable level
30
+ text such as "WARN"; the component does not generate it from the prop.
31
+
32
+ ## Sizes
33
+
34
+ No size variants. The product chooses the frame height. The frame uses
35
+ `--color-neutral-950`, text `--color-neutral-300`, `--color-border`,
36
+ `--radius-surface`, and `--spacing-md` padding. Log text uses `--font-mono`,
37
+ `--type-size-label`, and `--type-line-height-relaxed`. Timestamps use
38
+ `--color-neutral-600` with `--spacing-sm` after them.
39
+
40
+ ## States
41
+
42
+ | State | Behavior |
43
+ | --- | --- |
44
+ | following (initial default) | Changed children scroll to the end before paint. |
45
+ | reading older output | Scrolling away from the bottom pauses automatic following. |
46
+ | returned to end | Scrolling within 8px of the bottom resumes uncontrolled following. |
47
+ | controlled | `follow` determines whether child updates scroll to the end. |
48
+
49
+ Omit `follow` for internal state. To connect a Follow switch, pass `follow` and
50
+ update it in `onFollowChange`. The callback reports whether scrolling reaches
51
+ or leaves the bottom; the product must apply that value in controlled mode.
52
+ `follow=false` prevents automatic following even at the bottom.
53
+
54
+ The `LogViewHandle` ref exposes `scrollToBottom(behavior?: ScrollBehavior)`
55
+ for a "Jump to end" action. This scrolls the internal element; it does not set
56
+ a controlled `follow` value. Turning `follow` on also moves to the end.
57
+
58
+ The product supplies empty, loading, disconnected, and failed-source states.
59
+ A line at `level="error"` describes log content, not a failure of LogView.
60
+
61
+ ## Accessibility
62
+
63
+ Use an accessible label for the surrounding log region and visible labels for
64
+ Follow and Jump to end controls. Keep timestamps and levels readable as text.
65
+ LogView does not assign `role="log"`, a live region, or a tab stop by default.
66
+ Choose announcement behavior for the task; announcing every line of a busy
67
+ stream can overwhelm the reader. Verify keyboard access to the internal
68
+ scroller in the target browser. Root props do not configure that scroller.
69
+
70
+ ### Keyboard
71
+
72
+ No custom keymap. Scrolling uses browser behavior when the scroller is focused.
73
+ Follow and Jump to end use their Switch and Button keyboard contracts.
74
+
75
+ ## When to use
76
+
77
+ - A bounded stream of operational output beside configuration or resource details.
78
+ - Log history where readers can pause following by scrolling back.
79
+
80
+ ## When NOT to use
81
+
82
+ - Unbounded datasets requiring virtualization. LogView renders every supplied
83
+ child; the product must bound retention or choose a virtualized viewer.
84
+ - An editable terminal or command input. LogView does not emulate a terminal.
85
+ - Search, filtering, parsing, or fetching log data. Those belong to the product.
86
+
87
+ ## Radix/shadcn mapping
88
+
89
+ No dedicated log primitive. Kiso uses a native internal overflow scroller and
90
+ owns follow-tail state. A ScrollArea alone does not provide that behavior or
91
+ the `LogViewHandle` contract.
@@ -0,0 +1,58 @@
1
+ # Separator
2
+
3
+ ## Purpose
4
+
5
+ Separator draws a rule between adjacent content or controls. It can mark a
6
+ semantic section break when that boundary is not already expressed by markup.
7
+
8
+ ## Anatomy
9
+
10
+ A single rule with no children. Use `orientation` to choose its axis and
11
+ `decorative` to choose whether it carries separator semantics.
12
+
13
+ ## Variants
14
+
15
+ | Prop | Values | Meaning |
16
+ | --- | --- | --- |
17
+ | `orientation` | `horizontal` (default), `vertical` | Direction of the rule. |
18
+ | `decorative` | `true` (default), `false` | Visual-only rule or semantic content boundary. |
19
+
20
+ ## Sizes
21
+
22
+ A horizontal rule is 1px high. A vertical rule is 1px wide and stretches along
23
+ the parent's cross axis; its container must provide a height. Both consume
24
+ `--color-border`. Spacing around the rule belongs to its parent.
25
+
26
+ ## States
27
+
28
+ Static. No hover, focus, active, disabled, loading, or error state.
29
+
30
+ ## Accessibility
31
+
32
+ With `decorative=true`, the rule has no separator semantics. Use this when
33
+ headings, sections, or groups already express the boundary.
34
+
35
+ Set `decorative=false` when the rule itself communicates a meaningful break
36
+ between content sections. Hiding that boundary would remove information for
37
+ screen-reader users. Radix supplies `role="separator"` and the appropriate
38
+ orientation semantics. Neither mode is focusable or resizable.
39
+
40
+ ### Keyboard
41
+
42
+ No keymap and no tab stop.
43
+
44
+ ## When to use
45
+
46
+ - A quiet visual boundary between groups in a toolbar or detail view.
47
+ - A thematic break between content sections with `decorative=false`.
48
+
49
+ ## When NOT to use
50
+
51
+ - A draggable pane boundary. Use [Split / Splitter](split.md).
52
+ - A box around a content unit. Use [Card](card.md).
53
+ - Every list row when spacing already makes the grouping clear.
54
+
55
+ ## Radix/shadcn mapping
56
+
57
+ Uses Radix Separator, as does shadcn Separator. Kiso maps horizontal and
58
+ vertical orientations to its rule classes and defaults to decorative mode.
@@ -0,0 +1,93 @@
1
+ # Split / Pane / Splitter
2
+
3
+ ## Purpose
4
+
5
+ Split places related content side by side and lets the reader allocate width
6
+ between panes. Use it for a list and its detail, or configuration beside logs.
7
+ Two [Cards](card.md) group separate content; Split expresses a shared workspace
8
+ whose divider changes the space available to each side.
9
+
10
+ ## Anatomy
11
+
12
+ ```
13
+ Split
14
+ ├── Pane (sized by Splitter)
15
+ ├── Splitter
16
+ └── Pane (fills remaining space)
17
+ ```
18
+
19
+ Keep the parts as direct siblings. Splitter owns the size and writes a
20
+ percentage `flex-basis` onto the preceding Pane. The second Pane must fill
21
+ the remaining width, using the `grow` class in the React composition. Pane has
22
+ a zero minimum width and owns overflow scrolling. The product sets the layout
23
+ height and pane padding.
24
+
25
+ ## Variants
26
+
27
+ One horizontal arrangement of panes with a vertical divider. There is no
28
+ orientation prop or stacked resize mode. Omitting Splitter produces a static
29
+ split whose sizes belong to the product.
30
+
31
+ ## Sizes
32
+
33
+ | Splitter prop | Default | Contract |
34
+ | --- | --- | --- |
35
+ | `defaultSize` | `50` | Initial preceding-pane basis, as a percentage of Split width. |
36
+ | `min` | `25` | Lower bound for resize operations, in percent. |
37
+ | `max` | `75` | Upper bound for resize operations, in percent. |
38
+ | `step` | `2` | Percentage points moved by each arrow key press. |
39
+
40
+ Supply bounds within 0 to 100, `min <= defaultSize <= max`, and a positive
41
+ `step`. The initial value is used as supplied; resize operations clamp to the
42
+ bounds. `defaultSize` initializes internal state and is not a controlled size
43
+ prop. `onSizeChange(size)` reports changed percentages for optional product
44
+ persistence; the product can restore a saved value as `defaultSize` on mount.
45
+
46
+ The divider is 1px wide with an expanded pointer area. It consumes
47
+ `--color-border`, changing to `--color-ring` on hover or drag.
48
+
49
+ ## States
50
+
51
+ | State | Behavior |
52
+ | --- | --- |
53
+ | default | The preceding Pane uses the current percentage. |
54
+ | hover | The divider highlights and shows the column-resize cursor. |
55
+ | dragging | Pointer capture keeps resizing active outside the divider until release or cancellation. |
56
+ | focus | The divider remains keyboard operable and must have a visible focus indicator. |
57
+ | at a bound | Further movement toward that bound leaves the size unchanged. |
58
+
59
+ No disabled, loading, or error state. Content inside each Pane owns those states.
60
+
61
+ ## Accessibility
62
+
63
+ Splitter is a focusable `role="separator"` with `aria-orientation="vertical"`.
64
+ It exposes `aria-valuemin`, `aria-valuemax`, and a rounded `aria-valuenow`.
65
+ Its default accessible name is "Resize panes"; use a more specific `aria-label`
66
+ when the page has several splits. Keep the separator exposed to assistive
67
+ technology. A resizable divider is not decorative.
68
+
69
+ ### Keyboard
70
+
71
+ | Key | Result |
72
+ | --- | --- |
73
+ | Tab | Focus or leave the divider in normal tab order. |
74
+ | ArrowLeft / ArrowRight | Decrease / increase the preceding Pane by `step`. |
75
+ | Home / End | Set the preceding Pane to `min` / `max`. |
76
+
77
+ ## When to use
78
+
79
+ - A list-detail workspace where the reader needs more room on either side.
80
+ - Configuration and output that remain visible together.
81
+
82
+ ## When NOT to use
83
+
84
+ - Independent summary tiles. Use Cards in a grid.
85
+ - A static dividing rule. Use [Separator](separator.md).
86
+ - A narrow viewport that cannot fit both panes. The product must choose an
87
+ appropriate single-pane flow; Split does not collapse automatically.
88
+
89
+ ## Radix/shadcn mapping
90
+
91
+ No Radix resize primitive. shadcn Resizable is a behavioral reference, but
92
+ Kiso's Splitter owns its percentage directly. It does not expose panel-group
93
+ state, vertical layouts, or collapsible panels.
@@ -0,0 +1,85 @@
1
+ # Stat
2
+
3
+ ## Purpose
4
+
5
+ Stat presents one named metric with an optional change and context. It supplies
6
+ the metric layout and typography. [Card](card.md) supplies the surrounding
7
+ surface and border when the metric needs a tile.
8
+
9
+ ## Anatomy
10
+
11
+ ```
12
+ Stat
13
+ ├── StatHeader
14
+ │ ├── StatLabel (required)
15
+ │ └── StatDelta (optional)
16
+ ├── StatValue (required)
17
+ └── StatFoot (optional)
18
+ ```
19
+
20
+ StatHeader puts the label and delta on one line. StatValue includes the value
21
+ and any unit needed to read it. StatFoot explains the time window, baseline,
22
+ or supporting fact. StatDelta accepts content; the product supplies its sign,
23
+ arrow, number, and unit.
24
+
25
+ ## Variants
26
+
27
+ Stat has no variants. StatDelta uses the same `variant` names as
28
+ [Badge](badge.md), with an outline badge treatment.
29
+
30
+ | StatDelta variant | Meaning | Color token |
31
+ | --- | --- | --- |
32
+ | `neutral` (default) | Change without a judgment of health. | `--color-foreground` |
33
+ | `info` | Informational change. | `--color-info` |
34
+ | `success` | A beneficial or healthy change. | `--color-success` |
35
+ | `warning` | A change needing attention. | `--color-warning` |
36
+ | `danger` | A harmful or failed condition. | `--color-danger` |
37
+
38
+ Direction does not determine severity. Lower latency can be `success`; fewer
39
+ successful requests can be `danger`. State the direction and comparison in
40
+ text so color is not the only explanation.
41
+
42
+ ## Sizes
43
+
44
+ One size. Stat uses `--spacing-lg` padding and `--spacing-2xs` between slots.
45
+ The label and foot use `--type-size-label` and `--color-muted-foreground`.
46
+ The value uses `--type-size-display`, `--type-weight-semibold`,
47
+ `--type-line-height-tight`, `--type-letter-spacing-display`, and tabular
48
+ numerals. The foot has `--spacing-sm` above it. Delta uses
49
+ `--type-size-metadata`, `--type-weight-medium`, and `--spacing-xs` between
50
+ its content parts.
51
+
52
+ ## States
53
+
54
+ The default is a readable metric. The product replaces unknown values with
55
+ [Skeleton](skeleton.md), describes unavailable data explicitly, and supplies
56
+ stale or error context. Do not display zero as a substitute for missing data.
57
+ Stat has no interactive or disabled state.
58
+
59
+ ## Accessibility
60
+
61
+ The root and header are `div` elements; the text slots are `span` elements.
62
+ Keep the label, value, and comparison together in reading order. Include units
63
+ and time windows in text. Decorative arrows are hidden from assistive
64
+ technology. Stat does not create a live region; announce updates only when
65
+ the task needs them.
66
+
67
+ ### Keyboard
68
+
69
+ No keymap. Any accompanying action uses its own Button or Link.
70
+
71
+ ## When to use
72
+
73
+ - A dashboard metric with a label, value, and comparison period.
74
+ - A compact summary inside a Card or an existing section.
75
+
76
+ ## When NOT to use
77
+
78
+ - Comparing many records across columns. Use [Table](table.md).
79
+ - A set of descriptive facts about one object. Use [KV](kv.md).
80
+ - A status without a metric. Use Badge.
81
+
82
+ ## Radix/shadcn mapping
83
+
84
+ No dedicated Radix or shadcn Stat primitive. Compose metric text and Badge
85
+ visuals, with Card supplying an optional outer surface.
@@ -76,7 +76,7 @@ outline — which is how a violet design system ends up rendering grey.
76
76
  | `secondary` | Neutral button fill, range track, count badge; never text. | `neutral.700` | `neutral.300` |
77
77
  | `secondary-foreground` | Text on a `secondary` fill. | `foreground` | `foreground` |
78
78
  | `secondary-hover` | `secondary` fill on hover; never text. | `neutral.600` | `neutral.400` |
79
- | `selected` | Selected row, active nav item, highlighted result; never text. | `accent.900` | `accent.200` |
79
+ | `selected` | Selected row, active nav item, highlighted result; never text. One step past `accent-surface-hover`, so selection and hover stay apart. | `accent.800` | `accent.300` |
80
80
  | `selected-foreground` | Text on a `selected` fill. | `foreground` | `foreground` |
81
81
 
82
82
  `primary-foreground` and `danger-foreground` invert with their fill: near-black
package/kiso/ui.css CHANGED
@@ -745,6 +745,7 @@ table.table { width: 100%; border-collapse: collapse; font-size: var(--type-size
745
745
  .nav-group { display: grid; gap: var(--spacing-2xs); }
746
746
  .nav-group > .t-caps { padding-inline: var(--spacing-sm); margin-block-end: var(--spacing-2xs); }
747
747
  .nav-item {
748
+ position: relative; /* the current marker is drawn beside the item */
748
749
  display: flex; align-items: center; gap: var(--spacing-sm);
749
750
  height: var(--size-control-sm);
750
751
  padding-inline: var(--spacing-sm);
@@ -758,15 +759,53 @@ table.table { width: 100%; border-collapse: collapse; font-size: var(--type-size
758
759
  }
759
760
  .nav-item .icon { color: var(--color-subtle-foreground); }
760
761
  .nav-item:hover { background: var(--color-accent-surface-hover); color: var(--color-foreground); text-decoration: none; }
762
+
763
+ /* The current destination is marked beside the item rather than on it. A fill
764
+ would put "current" and "hovered" in the same language, one tint apart, in a
765
+ column where the pointer is usually resting on some other item. Leaving the
766
+ fill to hover keeps the two signals different in kind, and it gives the
767
+ marker the one thing a rail needs and a floating pill cannot offer — an edge
768
+ shared with every sibling, which in a column is the gutter. */
761
769
  .nav-item[aria-current="page"], .nav-item.active {
762
- background: var(--color-selected);
763
- box-shadow: inset 2px 0 0 var(--color-primary);
764
770
  color: var(--color-selected-foreground);
765
771
  font-weight: var(--type-weight-medium);
766
772
  }
773
+ .nav-item[aria-current="page"]::before, .nav-item.active::before {
774
+ content: "";
775
+ position: absolute;
776
+ inset-inline-start: calc(-1 * var(--spacing-sm)); /* the sidebar's own padding */
777
+ inset-block: 2px;
778
+ width: 2px;
779
+ border-radius: var(--radius-full);
780
+ background: var(--color-primary);
781
+ }
767
782
  .nav-item[aria-current="page"] .icon, .nav-item.active .icon { color: currentColor; }
768
783
  .nav-item .badge { margin-inline-start: auto; }
769
784
 
785
+ /* Navigation laid out in a row. The shared edge is now the bottom, so the same
786
+ marker moves there and the row grows a baseline for it to sit on — the
787
+ arrangement `.tabs` already uses. Without this the rail points at a gutter
788
+ that a horizontal row does not have. */
789
+ .nav-row {
790
+ display: flex; gap: var(--spacing-lg);
791
+ margin: 0; padding: 0; list-style: none;
792
+ border-bottom: 1px solid var(--color-border);
793
+ }
794
+ .nav-row .nav-item {
795
+ width: auto;
796
+ height: var(--size-control-lg);
797
+ padding-inline: 0;
798
+ border-radius: 0;
799
+ }
800
+ .nav-row .nav-item:hover { background: none; color: var(--color-foreground); }
801
+ .nav-row .nav-item[aria-current="page"]::before, .nav-row .nav-item.active::before {
802
+ inset-inline: 0;
803
+ inset-block: auto;
804
+ bottom: -1px;
805
+ width: auto;
806
+ height: 2px;
807
+ }
808
+
770
809
  .brand { display: flex; align-items: center; gap: var(--spacing-sm); min-width: 0; }
771
810
  .brand-mark {
772
811
  display: grid; place-items: center;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momoi-labs/kiso",
3
- "version": "0.4.1",
3
+ "version": "0.6.0",
4
4
  "description": "Kiso design-system contracts and generated design tokens",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -59,7 +59,7 @@
59
59
  --color-link: var(--color-primary);
60
60
  --color-accent-surface: light-dark(var(--color-accent-50), var(--color-accent-950));
61
61
  --color-accent-surface-hover: light-dark(var(--color-accent-200), var(--color-accent-900));
62
- --color-selected: light-dark(var(--color-accent-200), var(--color-accent-900));
62
+ --color-selected: light-dark(var(--color-accent-300), var(--color-accent-800));
63
63
  --color-selected-foreground: var(--color-foreground);
64
64
  --color-secondary: light-dark(var(--color-neutral-300), var(--color-neutral-700));
65
65
  --color-secondary-foreground: var(--color-foreground);
@@ -100,7 +100,7 @@ export const semanticLink: string;
100
100
  export const semanticAccentSurface: string;
101
101
  /** Accent tint one step stronger. Non-text role. */
102
102
  export const semanticAccentSurfaceHover: string;
103
- /** Selected row, active navigation item, highlighted palette result. Non-text role. */
103
+ /** Selected row, active navigation item, highlighted palette result. One ramp step past accent-surface-hover, so a selected item and a hovered sibling never paint the same surface. Non-text role. */
104
104
  export const semanticSelected: string;
105
105
  /** Text on a selected row. */
106
106
  export const semanticSelectedForeground: string;
@@ -56,7 +56,7 @@
56
56
  "semantic-link": {"colorSpace":"srgb","components":[0.7961,0.7412,0.9686],"hex":"#cbbdf7"},
57
57
  "semantic-accent-surface": {"colorSpace":"srgb","components":[0.1294,0.0902,0.2549],"hex":"#211741"},
58
58
  "semantic-accent-surface-hover": {"colorSpace":"srgb","components":[0.1804,0.1294,0.4392],"hex":"#2e2170"},
59
- "semantic-selected": {"colorSpace":"srgb","components":[0.1804,0.1294,0.4392],"hex":"#2e2170"},
59
+ "semantic-selected": {"colorSpace":"srgb","components":[0.2745,0.1882,0.6196],"hex":"#46309e"},
60
60
  "semantic-selected-foreground": {"colorSpace":"srgb","components":[0.9804,0.9765,0.9686],"hex":"#faf9f7"},
61
61
  "semantic-secondary": {"colorSpace":"srgb","components":[0.1922,0.1843,0.2157],"hex":"#312f37"},
62
62
  "semantic-secondary-foreground": {"colorSpace":"srgb","components":[0.9804,0.9765,0.9686],"hex":"#faf9f7"},
@@ -58,7 +58,7 @@ $semantic-primary-hover: #ded5fb; // Primary fill on hover — one ramp step awa
58
58
  $semantic-link: #cbbdf7; // Inline and standalone links.
59
59
  $semantic-accent-surface: #211741; // Faintest accent tint: row hover, ghost-button hover. Non-text role.
60
60
  $semantic-accent-surface-hover: #2e2170; // Accent tint one step stronger. Non-text role.
61
- $semantic-selected: #2e2170; // Selected row, active navigation item, highlighted palette result. Non-text role.
61
+ $semantic-selected: #46309e; // Selected row, active navigation item, highlighted palette result. One ramp step past accent-surface-hover, so a selected item and a hovered sibling never paint the same surface. Non-text role.
62
62
  $semantic-selected-foreground: #faf9f7; // Text on a selected row.
63
63
  $semantic-secondary: #312f37; // Neutral button fill, range track, count badge. Non-text role.
64
64
  $semantic-secondary-foreground: #faf9f7; // Text on a secondary fill.