@urbicon-ui/design-content 6.1.8

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 (111) hide show
  1. package/README.md +54 -0
  2. package/content/auth/components/account-settings/llm.txt +33 -0
  3. package/content/auth/components/forgot-password-page/llm.txt +25 -0
  4. package/content/auth/components/invitation-manager/llm.txt +28 -0
  5. package/content/auth/components/login-page/llm.txt +34 -0
  6. package/content/auth/components/notification-badge/llm.txt +21 -0
  7. package/content/auth/components/notification-center/llm.txt +33 -0
  8. package/content/auth/components/notification-listener/llm.txt +24 -0
  9. package/content/auth/components/passkey-manager/llm.txt +27 -0
  10. package/content/auth/components/push-permission-prompt/llm.txt +32 -0
  11. package/content/auth/components/register-page/llm.txt +35 -0
  12. package/content/auth/components/reset-password-page/llm.txt +26 -0
  13. package/content/auth/components/session-manager/llm.txt +32 -0
  14. package/content/auth/components/two-factor-manager/llm.txt +40 -0
  15. package/content/auth/components/verify-email-page/llm.txt +25 -0
  16. package/content/blocks/components/area-chart/llm.txt +46 -0
  17. package/content/blocks/components/bar-chart/llm.txt +44 -0
  18. package/content/blocks/components/calendar/llm.txt +105 -0
  19. package/content/blocks/components/chart-frame/llm.txt +38 -0
  20. package/content/blocks/components/command-palette/llm.txt +60 -0
  21. package/content/blocks/components/composition-bar/llm.txt +69 -0
  22. package/content/blocks/components/currency-input/llm.txt +65 -0
  23. package/content/blocks/components/date-picker/llm.txt +90 -0
  24. package/content/blocks/components/donut-chart/llm.txt +45 -0
  25. package/content/blocks/components/empty-state/llm.txt +43 -0
  26. package/content/blocks/components/file-upload/llm.txt +76 -0
  27. package/content/blocks/components/guide/llm.txt +49 -0
  28. package/content/blocks/components/guide-article/llm.txt +30 -0
  29. package/content/blocks/components/guide-beacon/llm.txt +38 -0
  30. package/content/blocks/components/guide-hint/llm.txt +41 -0
  31. package/content/blocks/components/guide-marker/llm.txt +36 -0
  32. package/content/blocks/components/guide-mention/llm.txt +31 -0
  33. package/content/blocks/components/guide-panel/llm.txt +42 -0
  34. package/content/blocks/components/guide-provider/llm.txt +31 -0
  35. package/content/blocks/components/line-chart/llm.txt +45 -0
  36. package/content/blocks/components/locale-switcher/llm.txt +44 -0
  37. package/content/blocks/components/planner/llm.txt +68 -0
  38. package/content/blocks/components/sankey/llm.txt +72 -0
  39. package/content/blocks/components/sidebar-layout/llm.txt +87 -0
  40. package/content/blocks/components/sparkline/llm.txt +33 -0
  41. package/content/blocks/components/theme-switcher/llm.txt +40 -0
  42. package/content/blocks/primitives/accordion/llm.txt +57 -0
  43. package/content/blocks/primitives/alert/llm.txt +54 -0
  44. package/content/blocks/primitives/avatar/llm.txt +61 -0
  45. package/content/blocks/primitives/badge/llm.txt +60 -0
  46. package/content/blocks/primitives/breadcrumb/llm.txt +47 -0
  47. package/content/blocks/primitives/button/llm.txt +80 -0
  48. package/content/blocks/primitives/button-group/llm.txt +65 -0
  49. package/content/blocks/primitives/card/llm.txt +68 -0
  50. package/content/blocks/primitives/checkbox/llm.txt +61 -0
  51. package/content/blocks/primitives/collapsible/llm.txt +66 -0
  52. package/content/blocks/primitives/combobox/llm.txt +86 -0
  53. package/content/blocks/primitives/confirm-dialog/llm.txt +47 -0
  54. package/content/blocks/primitives/dialog/llm.txt +59 -0
  55. package/content/blocks/primitives/drawer/llm.txt +54 -0
  56. package/content/blocks/primitives/form-field/llm.txt +43 -0
  57. package/content/blocks/primitives/input/llm.txt +73 -0
  58. package/content/blocks/primitives/menu/llm.txt +81 -0
  59. package/content/blocks/primitives/pagination/llm.txt +68 -0
  60. package/content/blocks/primitives/popover/llm.txt +72 -0
  61. package/content/blocks/primitives/progress/llm.txt +55 -0
  62. package/content/blocks/primitives/radio-group/llm.txt +53 -0
  63. package/content/blocks/primitives/segment-group/llm.txt +51 -0
  64. package/content/blocks/primitives/select/llm.txt +130 -0
  65. package/content/blocks/primitives/separator/llm.txt +45 -0
  66. package/content/blocks/primitives/sidebar/llm.txt +79 -0
  67. package/content/blocks/primitives/skeleton/llm.txt +54 -0
  68. package/content/blocks/primitives/slider/llm.txt +82 -0
  69. package/content/blocks/primitives/spinner/llm.txt +46 -0
  70. package/content/blocks/primitives/stepper/llm.txt +60 -0
  71. package/content/blocks/primitives/tab/llm.txt +72 -0
  72. package/content/blocks/primitives/textarea/llm.txt +61 -0
  73. package/content/blocks/primitives/toast/llm.txt +45 -0
  74. package/content/blocks/primitives/toggle/llm.txt +62 -0
  75. package/content/blocks/primitives/toolbar/llm.txt +60 -0
  76. package/content/blocks/primitives/tooltip/llm.txt +54 -0
  77. package/content/component-catalog.json +5010 -0
  78. package/content/design-system/patterns/dashboard.md +55 -0
  79. package/content/design-system/patterns/form-page.md +69 -0
  80. package/content/design-system/patterns/onboarding-guide.md +50 -0
  81. package/content/design-system/patterns/planning-board.md +46 -0
  82. package/content/design-system/patterns/settings-page.md +48 -0
  83. package/content/design-system/patterns/tab-navigation.md +136 -0
  84. package/content/design-system/principles.md +260 -0
  85. package/content/docs/components/api-reference/llm.txt +32 -0
  86. package/content/docs/components/code-example/llm.txt +44 -0
  87. package/content/docs/components/code-panel/llm.txt +26 -0
  88. package/content/docs/components/docs-layout/llm.txt +61 -0
  89. package/content/docs/components/info-card/llm.txt +31 -0
  90. package/content/docs/components/playground-configurator/llm.txt +49 -0
  91. package/content/docs/components/section/llm.txt +46 -0
  92. package/content/docs/components/table-of-contents/llm.txt +48 -0
  93. package/content/docs/components/types-reference/llm.txt +38 -0
  94. package/content/guides/llms-full-template.md +1019 -0
  95. package/content/icons.json +4834 -0
  96. package/content/meta.json +5 -0
  97. package/content/table/table/llm.txt +110 -0
  98. package/content/verbs/adopt.md +33 -0
  99. package/content/verbs/audit.md +29 -0
  100. package/content/verbs/compose.md +38 -0
  101. package/content/verbs/critique.md +27 -0
  102. package/content/verbs/fix.md +29 -0
  103. package/content/verbs/migrate.md +30 -0
  104. package/content/verbs/onboard.md +33 -0
  105. package/content/verbs/polish.md +25 -0
  106. package/content/verbs/redesign.md +29 -0
  107. package/content/verbs/retheme.md +29 -0
  108. package/package.json +45 -0
  109. package/src/content-loader.test.ts +78 -0
  110. package/src/content-loader.ts +97 -0
  111. package/src/index.ts +23 -0
@@ -0,0 +1,5 @@
1
+ {
2
+ "version": "6.1.8",
3
+ "builtAt": "2026-06-22T12:20:10.242Z",
4
+ "contentHash": "20b83a8bdb37"
5
+ }
@@ -0,0 +1,110 @@
1
+
2
+ ---
3
+
4
+ ## Table
5
+ Advanced data table component with smart filtering, column factories, responsive design,
6
+ and extensible features for complex data visualization. Supports row selection, keyboard navigation,
7
+ virtual scrolling, column reorder, server-side data, live updates, and custom cell components.
8
+
9
+ **Import:** `import { Table } from '@urbicon-ui/table';`
10
+
11
+ ### Examples
12
+ ```svelte
13
+ <Table
14
+ items={data}
15
+ columns={columns}
16
+ itemsPerPage={25}
17
+ enableSmartFilter={true}
18
+ />
19
+ ```
20
+
21
+ ```svelte
22
+ {#snippet statusCell(item, value)}
23
+ <Badge intent={value === 'active' ? 'success' : 'danger'}>{value}</Badge>
24
+ {/snippet}
25
+
26
+ <Table items={data} columns={[
27
+ { accessor: 'name', title: 'Name', sortable: true },
28
+ { accessor: 'status', title: 'Status', cell: statusCell }
29
+ ]} />
30
+ ```
31
+
32
+ ```svelte
33
+ <Table
34
+ items={data}
35
+ columns={columns}
36
+ selectionMode="multi"
37
+ onSelectionChange={(selected) => console.log(selected)}
38
+ />
39
+ ```
40
+
41
+ ```svelte
42
+ <Table
43
+ mode="server"
44
+ columns={columns}
45
+ queryFn={async (query, { signal }) => {
46
+ const res = await fetch(`/api/users?page=${query.page}`, { signal });
47
+ return await res.json();
48
+ }}
49
+ />
50
+ ```
51
+
52
+ ```svelte
53
+ <Table items={tenThousandRows} columns={columns} virtualized virtualHeight="500px" />
54
+ ```
55
+
56
+ ```svelte
57
+ <Table {items} {columns} persistenceConfig={{ tableId: 'expenses' }} />
58
+ ```
59
+
60
+ ### Api
61
+ | Prop | Type | Required | Default | Description |
62
+ | --- | --- | :---: | --- | --- |
63
+ | appearance | `'flush' | 'surface' | 'framed'` | no | "flush" | Visual appearance of the table chrome (see docs/MIGRATION-v5.md §3): - `flush` (default): no outer frame, sits inline in the reading flow - `surface`: gentle `surface-quiet` tinted zone, no border - `framed`: bordered + rounded + shadowed standalone block |
64
+ | ariaLabel | `string` | no | undefined | Accessible label for the table, announced by screen readers. |
65
+ | autoApplyOnNavigation | `boolean` | no | true | Automatically apply pending live updates when the user navigates (page change, sort, filter, search). Since the view is already changing, applying buffered changes at this point is non-disruptive. |
66
+ | body | `Snippet` | no | undefined | Body property for the Table component |
67
+ | cell | `Snippet<[item: T, value: unknown, column: Column<T>]>` | no | undefined | Global cell snippet that overrides rendering for ALL columns. For per-column customization, prefer `column.cell` instead. |
68
+ | class | `string` | no | undefined | Additional CSS class names for the table container |
69
+ | columns | `Column<T>[]` | no | [] | Column configuration array defining the table structure |
70
+ | empty | `Snippet` | no | undefined | Custom empty state snippet |
71
+ | enableColumnReorder | `boolean` | no | false | Enable drag-and-drop column reordering on desktop. Users can drag column headers to rearrange them. Also supports keyboard reorder via Shift+ArrowLeft/Right on focused headers. |
72
+ | enableLiveUpdates | `boolean` | no | false | Enable live update support. When enabled, a `LiveUpdateBanner` is shown when pending inserts/updates/deletes are buffered. Use `getTableContext()` to access `pushInsert`, `pushUpdate`, `pushDelete` from WebSocket/SSE handlers. |
73
+ | enableSmartFilter | `boolean` | no | true | Enable smart filtering functionality |
74
+ | error | `Snippet` | no | undefined | Custom error state snippet |
75
+ | errorText | `string` | no | "Error loading data" | Text displayed on error |
76
+ | expandedRowContent | `Snippet<[item: T]>` | no | undefined | Snippet to render expanded row content |
77
+ | fit | `'content' | 'viewport'` | no | "content" | Make the table its own scroll container so wide **and** long lists scroll *within* the table instead of pushing overflow onto the page. - `'content'` (default): the table grows with its content; vertical overflow scrolls the page. Pair with `sticky` for page-relative pinning. - `'viewport'`: the table is height-capped to the viewport and becomes a self-contained scroll box. The column header (and group header when grouping) pin to the top of the box, while the toolbar and pagination stay fixed outside the scrolling area — only the rows scroll, in both axes. The available height is measured automatically (the container's distance from the top of the viewport), so no magic `max-height` is needed in the consumer, and it adapts to whatever sits above the table (tabs, banners). Notes for `'viewport'`: - Desktop only (`md`+); mobile keeps normal document-level scroll. - Supersedes `sticky`: header/group pinning is intrinsic to the box, so the `sticky` prop is ignored. `stickyOffset` is ignored too — the measured top absorbs app-shell offsets automatically. - Mutually exclusive with `virtualized`, which manages its own bounded scroll via `virtualHeight`; `fit` has no effect when `virtualized`. |
78
+ | groupHeaderContent | `Snippet<[groupName: string, items: T[], isExpanded: boolean]>` | no | null | Custom content for group headers |
79
+ | groupOrder | `string[]` | no | [] | Custom order for group display |
80
+ | header | `Snippet` | no | undefined | Custom header snippet |
81
+ | initialGroupBy | `string | null` | no | null | Initial grouping key (if no persisted value exists). When grouping is active, pagination is disabled — all grouped items are shown at once. |
82
+ | initialPage | `number` | no | 1 | InitialPage property for the Table component |
83
+ | initialSummaryConfigs | `SummaryConfig[]` | no | [] | Initial summary configurations (if no persisted value exists). Each entry defines a column + aggregation type (sum, avg, count, min, max). |
84
+ | items | `T[]` | no | [] | Array of data items to display in the table. Items with an `id` property get better key stability for animations. If no `id` is present, the array index is used as fallback key. |
85
+ | itemsPerPage | `number` | no | 10 | Number of items to display per page |
86
+ | loading | `Snippet` | no | undefined | Custom loading state snippet |
87
+ | loadingText | `string` | no | "Loading data..." | Text displayed during loading state |
88
+ | mode | `'client' | 'server'` | no | "client" | Data processing mode. - `'client'` (default): Filtering, sorting, and pagination are done locally. - `'server'`: The table delegates all data operations to the server. Items passed via `items` prop (or returned by `queryFn`) are displayed as-is. |
89
+ | multiExpand | `boolean` | no | false | Allow multiple rows to be expanded simultaneously. When false (default), expanding a row collapses the previously expanded one. |
90
+ | noDataText | `string` | no | "No data found." | Text displayed when no data is available |
91
+ | onQueryChange | `(query: TableQuery) => void` | no | undefined | Callback fired when the table query changes in `mode: 'server'`. Use this for manual control — fetch data yourself and update `items`, `serverTotalItems`, `loading`, and `error` props accordingly. Fires after debounce (controlled by `queryDebounceMs`). |
92
+ | onRowClick | `(item: T) => void` | no | undefined | Callback fired when a row is clicked. Receives the clicked row's data item. |
93
+ | onSelectionChange | `(selectedItems: T[]) => void` | no | undefined | Callback fired when the selection changes. Receives the array of currently selected items. |
94
+ | pagination | `Snippet` | no | undefined | Custom pagination snippet |
95
+ | persistenceConfig | `TablePersistenceConfig` | no | undefined | Persist table view state across reloads. Pass `{ tableId: 'foo' }` to opt in — every axis (filters, search, group, summary, sort, column visibility, column order) is persisted by default into `localStorage` under keys scoped to `tableId`. Set individual `persist*` flags to `false` to keep an axis volatile. Pagination (current page) is intentionally never persisted — page 1 on navigation is standard UX. |
96
+ | queryDebounceMs | `number` | no | 300 | Debounce delay in milliseconds for server query changes. Prevents excessive requests during rapid filter/search input. |
97
+ | queryFn | `(query: TableQuery, options: { signal: AbortSignal }) => Promise<TableQueryResult>` | no | | Async function for managed server-side fetching. When provided in `mode: 'server'`, the table calls this function automatically when the query changes (debounced). The table manages loading/error states and request cancellation via `AbortSignal`. |
98
+ | searchDebounceMs | `number` | no | 300 | Debounce delay for search in milliseconds |
99
+ | searchPlaceholder | `string` | no | "Search..." | Placeholder text for search input |
100
+ | selectedIds | `Array<string | number>` | no | undefined | Controlled selected row IDs. When provided, the component reflects this value instead of managing selection internally. |
101
+ | selectionMode | `'none' | 'single' | 'multi'` | no | "none" | Row selection mode. - `'none'`: No selection (default) - `'single'`: Only one row can be selected at a time - `'multi'`: Multiple rows can be selected with checkboxes |
102
+ | serverTotalItems | `number` | no | 0 | Total number of items on the server. Required when `mode` is `'server'` and manual control is used (without `queryFn`). Drives pagination calculation. |
103
+ | size | `'sm' | 'md' | 'lg'` | no | "md" | Size variant for the table |
104
+ | slotClasses | `Partial<TableSlotClasses>` | no | {} | Per-slot class overrides merged with (or replacing, if `unstyled`) variant styles. Available slots: `container`, `toolbar`, `scrollArea`, `table`, `thead`, `tbody`, `headerRow`, `headerCell`, `row`, `cell`, `groupHeader`, `summaryRow`, `emptyState`, `loadingState`, `errorState`, `filterBar`, `mobileCard`. **Breaking change in v1.5:** the former `wrapper` slot has been replaced by `scrollArea`. The former hardcoded `overflow-hidden` on `wrapper` blocked `position: sticky`, see [docs/STICKY-PINNING.md](../../../../../docs/STICKY-PINNING.md). |
105
+ | sticky | `boolean | 'toolbar' | 'header' | 'both'` | no | false | Pin toolbar/header/group-header to the top of the scroll ancestor on scroll. - `false` (default): no pinning, layout matches v1.4.x - `true` / `'both'`: toolbar + thead + group-header all pin - `'toolbar'`: only the toolbar pins - `'header'`: only the thead (and group-header when grouping is active) pins Pair with `stickyOffset` for app shells that have a fixed top bar. For tables wider than the viewport, prefer `fit="viewport"` — it contains horizontal scroll inside the table instead of falling back to page-level horizontal scroll (a sticky pin host cannot also be a horizontal scroll ancestor). `fit="viewport"` supersedes `sticky` when set. |
106
+ | stickyOffset | `number` | no | 0 | Pixel offset for the topmost sticky layer (toolbar, or thead when no toolbar). Writes the CSS custom property `--blocks-table-sticky-top` on the container. Use this to push the pin below a fixed app shell top bar. |
107
+ | toolbar | `Snippet` | no | undefined (renders default SmartFilterBar when enableSmartFilter) | Custom toolbar snippet. Replaces the default `SmartFilterBar`. Renders inside the sticky toolbar wrapper when `sticky` is enabled — so a custom toolbar inherits the pinning behavior without extra wiring. Access the table context via `getTableContext()` to wire up custom filter UIs. |
108
+ | unstyled | `boolean` | no | false | Remove default tailwind-variants classes. Only user-provided `slotClasses` apply. |
109
+ | virtualHeight | `string` | no | "600px" | Height of the virtual scroll container. Only used when `virtualized` is true. Accepts any CSS height value. |
110
+ | virtualized | `boolean` | no | false | Enable virtualization for large datasets. When enabled, only visible rows are rendered for performance with >1000 items. Pagination is bypassed — all filtered/sorted items are virtualized in a scrollable container. Not compatible with grouping (grouping takes precedence). |
@@ -0,0 +1,33 @@
1
+ # adopt — bring an existing codebase under the design system
2
+
3
+ **When:** a project already has UI but no (or a thin) `design.manifest.md`. Infers
4
+ the de-facto design language from the code and records it, surfacing the drift
5
+ between what the code does and what Urbicon expects.
6
+ **Gate:** none — this verb writes memory and reports; it doesn't rewrite UI.
7
+
8
+ 1. **Read what's already recorded.** `urbicon context`. Anything present (a chosen
9
+ paradigm, a prior ADR) constrains what you infer — don't contradict it silently.
10
+ 2. **Index the patterns.** `urbicon sync-manifest` to scan for
11
+ `data-design-pattern="…"` markers and (re)build the Pattern Usages section. If
12
+ the code has no markers yet, note which page archetypes you recognise and propose
13
+ adding markers (see `get_pattern` for the archetype names).
14
+ 3. **Infer the token reality.** Grep the source for the colour / spacing / radius
15
+ utilities actually in use. Sort them into: real Urbicon semantic tokens; project
16
+ tokens defined on top of Urbicon (→ candidates for `## Token Overrides`); and raw
17
+ palette / hallucinated tokens (→ drift to fix later with `fix`). Cross-check
18
+ names against `get_css_reference`.
19
+ 4. **Infer the intent.** From the components, copy, and density, draft a **Product
20
+ Intent** (audience, voice, references, anti-references) and confirm it with the
21
+ user — inference seeds it, the user ratifies it. Don't invent an audience the
22
+ code doesn't evidence.
23
+ 5. **Measure the drift.** Run `urbicon validate src/ --record` over the tree. The
24
+ correctness score is the gap to close; the slop-floor score is how generic it
25
+ reads today. `--record` writes the first history entry so future runs show the
26
+ trend.
27
+ 6. **Seed the manifest.** Write the inferred `## Product Intent`, the confirmed
28
+ `## Token Overrides`, and the synced `## Pattern Usages`. Append an ADR recording
29
+ that the manifest was *adopted from existing code* on this date (so later readers
30
+ know it's inferred, not designed-first).
31
+ 7. **Report.** Summarise: paradigm, intent, N project tokens, M patterns in use, and
32
+ the top correctness/slop offenders — with `fix` / `retheme` / `audit` as the
33
+ suggested follow-ups.
@@ -0,0 +1,29 @@
1
+ # audit — check design consistency across the whole app
2
+
3
+ **When:** a periodic or pre-release sweep — is the app still coherent, or has it
4
+ drifted? The flagship cross-page verb: it reasons over *many* surfaces via the
5
+ manifest usage-index, which no single-page or system-agnostic tool can do.
6
+ **Gate:** none — assessment over n pages. Change nothing; produce a drift report.
7
+
8
+ 1. **Context + index.** `urbicon context` for the intent and recorded decisions, then
9
+ `urbicon sync-manifest` so the Pattern Usages index reflects the current tree.
10
+ 2. **Validate the tree.** `urbicon validate src/ --json --record` over the whole app.
11
+ `--record` appends a drift entry to the history sidecar; `urbicon context` then
12
+ shows the correctness/slop trend over time — the measure of whether the app is
13
+ getting more or less generic.
14
+ 3. **Check each pattern cohort.** For every pattern in the usage-index, read the files
15
+ listed under it and confirm they actually follow that pattern's rules
16
+ (`get_pattern("<name>")`). A page marked `dashboard` that looks like a form is
17
+ drift.
18
+ 4. **Score a representative sample.** Pick the highest-traffic or most-divergent pages
19
+ and score them with `get_design_principles(as="rubric")`. Look for *spread* — wide
20
+ variance across pages is the consistency problem, even if each page passes alone.
21
+ 5. **Report drift, don't fix it.** Produce: the app-wide correctness/slop scores and
22
+ their trend; per-pattern conformance; the rubric spread; and a ranked list of the
23
+ worst offenders, each tagged with the verb that repairs it (`fix`, `polish`,
24
+ `redesign`, `retheme`).
25
+ 6. **Persist the finding.** Offer to append an ADR summarising the audit (date,
26
+ scores, top drift) so the next audit has a baseline to compare against — the
27
+ history sidecar plus an ADR make drift measurable, not anecdotal.
28
+
29
+ Output: the drift report. Recommend, but do not perform, the repairs.
@@ -0,0 +1,38 @@
1
+ # compose — design a new page or component from a brief
2
+
3
+ **When:** building something new. Runs the full generate → validate → judge →
4
+ synthesise loop so a single-shot answer can't regress to a generic template.
5
+ **Gate:** correctness (blocking) + slop-floor (advisory) + the rubric.
6
+
7
+ Do not skip steps. The value is in the loop, not any one generation.
8
+
9
+ 1. **Context.** `urbicon context` (or read `./design.manifest.md`) — honour the
10
+ paradigm, theme, density, the Product Intent (design *toward* its voice and
11
+ references, *away* from its anti-references), and the recorded ADRs. Then, if a
12
+ composition pattern fits the brief, `get_pattern("<name>")` (settings-page,
13
+ dashboard, form-page, tab-navigation, onboarding-guide, planning-board) and
14
+ follow its layout, component-selection, and behavioural rules.
15
+ 2. **Ground rules.** `get_design_principles` for the heuristics,
16
+ `get_design_principles(topic="theming")` for the paradigm's token profile, and
17
+ `get_css_reference` for the exact token names. `find_components` /
18
+ `suggest_implementation` to pick the right primitives rather than reinventing them.
19
+ 3. **Generate variants.** Produce a few genuinely different implementations (2–5;
20
+ default 3), each a distinct compositional approach *within* the paradigm — vary
21
+ density, hierarchy emphasis, and the one signature moment. Do not let them
22
+ converge. Use only real semantic tokens (no `bg-status-*`, no `*-foreground`, no
23
+ invented names); if the project defines its own, they're in `## Token Overrides`.
24
+ 4. **Validate.** Run `validate_design` (or `urbicon validate`) on every variant. Fix
25
+ each error and warning. A variant that can't reach a clean correctness score is
26
+ disqualified. Note each one's slop-floor score — lower is more generic.
27
+ 5. **Judge.** `get_design_principles(as="rubric")` and score each survivor /40.
28
+ Prefer a panel: judge correctness, hierarchy, paradigm-fidelity, and
29
+ distinctiveness as separate lenses, not one gut number.
30
+ 6. **Synthesise.** Pick the winner, then graft the best ideas from the runners-up.
31
+ Run `validate_design` once more on the merged result — it must come back clean.
32
+ 7. **Record.** If the page follows a pattern, add `data-design-pattern="<name>"` to
33
+ its root and refresh Pattern Usages (`urbicon sync-manifest`). Append an ADR
34
+ (`urbicon record-decision`) for any deliberate deviation from a pattern or
35
+ principle.
36
+
37
+ Output the final code, then a one-line, honest rationale per major choice — name the
38
+ trade-offs.
@@ -0,0 +1,27 @@
1
+ # critique — judge a page without changing it
2
+
3
+ **When:** the user wants an assessment, a review, or a prioritised punch-list — not
4
+ edits. Produces a diagnosis you (or `redesign` / `polish` / `fix`) can act on later.
5
+ **Gate:** none — this verb only assesses. Change nothing.
6
+
7
+ 1. **Context.** `urbicon context` for the paradigm and Product Intent — a critique
8
+ is *against this project's* identity, not a generic best-practices checklist.
9
+ 2. **Run the full stack.** On the page's code:
10
+ - **Correctness** — `validate_design` (or `urbicon validate`): errors and warnings
11
+ are deterministic defects (raw colours, `dark:`/`focus:` misuse, hardcoded
12
+ z-index, broken dynamic classes, hallucinated tokens).
13
+ - **Slop-floor** — the same run's advisory notes: where it reads generic.
14
+ - **Taste** — `get_design_principles(as="rubric")` and score /40 across the eight
15
+ criteria.
16
+ 3. **Prioritise.** Order the findings by impact, not by severity label: a single
17
+ broken hierarchy outranks five cosmetic nits. Tie each to the rubric criterion or
18
+ linter rule it comes from, so the fix is unambiguous.
19
+ 4. **Recommend the verb.** For each cluster, name the right follow-up — `fix` for
20
+ correctness, `polish` for slop, `redesign` for a low rubric score — so the user
21
+ can act in one step.
22
+ 5. **Offer to record.** If the critique surfaces a *systemic* gap (not a one-page
23
+ issue), offer to append an ADR or open it as drift in the manifest. Don't write
24
+ without asking — critique's contract is read-only.
25
+
26
+ Output: the two scores (correctness · slop-floor), the rubric /40 with the two
27
+ weakest criteria called out, and the prioritised fix-list with a verb per item.
@@ -0,0 +1,29 @@
1
+ # fix — repair correctness defects
2
+
3
+ **When:** the linter's blocking gate is red — raw Tailwind colours, `dark:` overrides,
4
+ `focus:` instead of `focus-visible:`, hardcoded z-index, broken dynamic classes, or
5
+ hallucinated tokens. Mechanical, behaviour-preserving corrections.
6
+ **Gate:** correctness — every error and warning must clear.
7
+
8
+ 1. **Context.** `urbicon context` — so a token you're tempted to "fix" that is
9
+ actually a declared project token (in `## Token Overrides`) is left alone. Pass
10
+ those as `extraTokens` to `validate_design`; `urbicon validate` reads them from the
11
+ manifest automatically.
12
+ 2. **Enumerate.** Run `validate_design` (or `urbicon validate`) and list every
13
+ **error** and **warning** with its rule id and location. Ignore the slop-floor
14
+ notes here — that's `polish`.
15
+ 3. **Map each to its correct token.** `get_css_reference` for the real names:
16
+ - raw palette (`bg-red-500`) → the semantic intent (`bg-danger`, `text-on-primary`).
17
+ - `dark:` override → delete it; semantic tokens handle dark mode via `light-dark()`.
18
+ - `focus:` → `focus-visible:`.
19
+ - hardcoded z-index → a `z-[var(--z-*)]` token.
20
+ - hallucinated token (`bg-status-danger`, `text-*-foreground`) → the real one, or a
21
+ `## Token Override` if the project genuinely defines it.
22
+ 4. **Apply and re-validate.** Make the substitutions, change nothing else, and run the
23
+ linter again. Repeat until correctness is clean. Behaviour and layout must be
24
+ identical — this verb does not redesign.
25
+ 5. **Record only a systemic fix.** A scattered cleanup needs no ADR. If you
26
+ discovered the project legitimately needs a token, add it to `## Token Overrides`
27
+ (so it stops being flagged) and note why.
28
+
29
+ Output the diff and confirm a clean correctness score.
@@ -0,0 +1,30 @@
1
+ # migrate — roll out a pattern or library change everywhere
2
+
3
+ **When:** a composition pattern, component API, or library convention changed and
4
+ every site of it must move in lockstep — e.g. "the settings-page pattern now uses
5
+ tabs" or "Card lost its `elevated` prop".
6
+ **Gate:** correctness per file — each migrated file must pass before the next.
7
+
8
+ 1. **Context.** `urbicon context` — the manifest's decisions tell you which
9
+ conventions are deliberate (don't migrate away from a recorded ADR without
10
+ superseding it).
11
+ 2. **Pin the before/after.** State the exact change: old construct → new construct.
12
+ If it's a pattern change, re-read both via `get_pattern`; if a component API change,
13
+ `get_component` for the new contract.
14
+ 3. **Find every site.** `urbicon sync-manifest`, then use the Pattern Usages index
15
+ (for pattern changes) and a grep of the old construct (for API/markup changes) to
16
+ enumerate the files. Report the count up front — a silently partial migration is
17
+ worse than none.
18
+ 4. **Transform file by file.** Apply the change to one file, run `validate_design` /
19
+ `urbicon validate`, and only then move on. Keep each file's diff minimal and
20
+ behaviour-preserving. If a file resists the mechanical transform, flag it for
21
+ manual `redesign` rather than forcing it.
22
+ 5. **Re-index and validate the whole.** `urbicon sync-manifest` again so the index
23
+ reflects the new reality, then `urbicon validate src/ --record` for a clean
24
+ end-state baseline.
25
+ 6. **Record the migration.** Append an ADR: what changed, why, how many files moved,
26
+ and any deliberately skipped (with the reason). The next person needs to know the
27
+ migration is complete and where the exceptions are.
28
+
29
+ Output: the file count, the per-file pass status, and any sites deferred to manual
30
+ follow-up.
@@ -0,0 +1,33 @@
1
+ # onboard — set a greenfield project's design identity
2
+
3
+ **When:** a new project with no `design.manifest.md` yet. Establishes the target
4
+ identity and the enforced intake decisions, so every later verb has an anchor.
5
+ **Gate:** none — this verb writes memory, it doesn't generate UI.
6
+
7
+ Run a short interview, then seed the manifest. Do not skip the interview: a manifest
8
+ with only defaults gives later verbs nothing to be consistent *with*.
9
+
10
+ 1. **Check for an existing manifest.** `urbicon context` (or look for
11
+ `./design.manifest.md`). If one already exists with real intent, stop and suggest
12
+ `adopt` or `audit` instead — onboarding twice overwrites a considered identity.
13
+ 2. **Interview the product intent.** Ask the user — one question at a time, accept
14
+ terse answers — for:
15
+ - **Audience:** who uses this, their context, constraints, expertise.
16
+ - **Voice:** three adjectives (e.g. *calm, precise, trustworthy*).
17
+ - **References:** one or two products whose feel to move toward.
18
+ - **Anti-references:** the generic defaults to avoid (e.g. "Bootstrap admin").
19
+ 3. **Settle the intake decisions.** Pick a **paradigm** (call
20
+ `get_design_principles(topic="theming")` to see the profiles), a **theme**, and a
21
+ **density**. Explain the trade-off in one line each; default to Minimal /
22
+ default / comfortable if the user is unsure.
23
+ 4. **Seed the manifest.** Write `./design.manifest.md`: the frontmatter
24
+ (`paradigm` / `theme` / `density`), and the `## Product Intent` section with the
25
+ interview answers. `urbicon` writes a scaffold on first command, or author the
26
+ file directly — keep the section headings exactly (`## Product Intent`,
27
+ `## Token Overrides`, `## Pattern Usages`, `## Design Decisions`).
28
+ 5. **Record the founding decision.** Append one ADR capturing *why* this paradigm
29
+ and voice (`urbicon record-decision --title "…" --decision "…" --rationale "…"`).
30
+ It is the reference the team — and the next session — argues against.
31
+ 6. **Hand off.** Tell the user the identity is set and point them at `compose` for
32
+ the first page. Confirm the manifest parses: `urbicon context` should echo the
33
+ intent back.
@@ -0,0 +1,25 @@
1
+ # polish — tighten a page that is already close
2
+
3
+ **When:** the structure is right but it reads a little generic — uniform spacing, a
4
+ default font, low-contrast text, a magic-number size. Small targeted fixes, no
5
+ rebuild.
6
+ **Gate:** slop-floor (the advisory "looks generic" axis) — and never regress
7
+ correctness.
8
+
9
+ 1. **Context.** `urbicon context` for the Product Intent — polish moves the page
10
+ *toward* its voice, not toward your taste.
11
+ 2. **Find the slop.** Run `validate_design` (or `urbicon validate`) and read the
12
+ **slop-floor** findings specifically (the advisory notes): generic font, uniform
13
+ spacing/weights, identical cards, grey-on-colour, animated dimensions,
14
+ magic-number sizes, small touch targets, emoji-as-icon, and so on.
15
+ 3. **Fix the smallest things that raise the slop-floor score.** One change at a time;
16
+ keep each reversible. Reach for the design system's real tokens and scale steps —
17
+ `get_css_reference` for names — rather than ad-hoc values. Do **not** restructure;
18
+ if a finding needs structural change, that's `redesign`, not `polish`.
19
+ 4. **Re-validate.** Run the linter again. The correctness score must not drop; the
20
+ slop-floor score should rise. Stop when the remaining findings are deliberate.
21
+ 5. **Record only if it's a rule.** A one-off tweak needs no ADR. If you set a
22
+ repeatable convention (e.g. "stat tiles use `surface-elevated`, not a border"),
23
+ append an ADR so the next page inherits it.
24
+
25
+ Output the diff (or the changed snippets) and the slop-floor score before → after.
@@ -0,0 +1,29 @@
1
+ # redesign — rework an existing page that feels wrong
2
+
3
+ **When:** a page exists but underperforms — flat, generic, off-identity. Diagnoses
4
+ first, then fixes exactly what the diagnosis flags, preserving behaviour.
5
+ **Gate:** correctness (blocking) + slop-floor (advisory) + the rubric.
6
+
7
+ A diagnosis-first loop — resist the urge to rebuild from scratch.
8
+
9
+ 1. **Context.** `urbicon context` (or read `./design.manifest.md`) to recover the
10
+ paradigm, theme, Product Intent, and prior decisions. Read the current
11
+ implementation of the page in question.
12
+ 2. **Diagnose.** Run `validate_design` (or `urbicon validate`) on the current code,
13
+ then `get_design_principles(as="rubric")` and score the page /40. Your revision
14
+ targets are **every linter finding** (correctness *and* slop-floor) plus the
15
+ **two lowest-scoring rubric criteria** — nothing else. Write the targets down.
16
+ 3. **Generate variants.** Produce a few options (2–5; default 3) that fix exactly
17
+ those weaknesses. Preserve the page's behaviour, data flow, and overall structure;
18
+ change only what the diagnosis flagged. Use only real tokens (project tokens are
19
+ in `## Token Overrides`).
20
+ 4. **Validate.** Run the linter on each; fix every error and warning.
21
+ 5. **Judge.** Re-score each variant with the rubric. A redesign that does not beat
22
+ the original on its target criteria is not shippable — say so and iterate.
23
+ 6. **Synthesise.** Merge the best result, then run `validate_design` once more — it
24
+ must come back clean.
25
+ 7. **Record.** Append an ADR for any deliberate deviation (`urbicon record-decision`);
26
+ refresh Pattern Usages (`urbicon sync-manifest`) if pattern usage changed.
27
+
28
+ End with a before/after table of the targeted criteria (old score → new score), then
29
+ the final code and a one-line, honest rationale per major change.
@@ -0,0 +1,29 @@
1
+ # retheme — rebrand the system across every surface
2
+
3
+ **When:** the design language itself changes — new brand colour, type, density, or
4
+ paradigm — and it must propagate everywhere consistently. The flagship verb: only
5
+ possible because there's a real token system plus a manifest usage-index to drive it.
6
+ **Gate:** correctness over every affected file.
7
+
8
+ 1. **Context + scope.** `urbicon context` for the current paradigm, theme, and
9
+ `## Token Overrides`. State precisely what's changing and what's staying — a
10
+ retheme that touches everything is a rewrite, not a rebrand.
11
+ 2. **Decide at the right layer.** `get_design_principles` includes a change-decision
12
+ tree: a colour shift is usually a **semantic-token** remap, not a per-component
13
+ edit. Change the foundation/semantic layer (or the project's `## Token Overrides`),
14
+ not 200 call-sites — that's the whole point of the token architecture.
15
+ 3. **Update the source of truth.** Apply the token changes once at the layer you
16
+ chose, and update `## Token Overrides` in the manifest so `validate` accepts the
17
+ new vocabulary and rejects the old.
18
+ 4. **Find every affected surface.** Use the manifest's Pattern Usages and a grep of
19
+ the changed token names to list the files that actually render them. The
20
+ usage-index is what makes "everywhere" tractable instead of a guess.
21
+ 5. **Propagate and validate per file.** For each affected file, apply the remap and
22
+ run `validate_design` / `urbicon validate`. The gate is per file: none may ship
23
+ with a stale or raw token. `urbicon validate src/ --record` at the end captures the
24
+ post-retheme drift baseline.
25
+ 6. **Record the rebrand.** Append one ADR describing the change, the layer it was made
26
+ at, and the old→new token mapping — the migration note future readers need.
27
+
28
+ Output: the layer-level change, the list of propagated files, and a clean
29
+ correctness score across all of them.
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@urbicon-ui/design-content",
3
+ "version": "6.1.8",
4
+ "description": "Version-pinned bundle of Urbicon UI design knowledge — component catalog, per-component llm.txt, design-system principles + patterns, guide template and icon metadata — plus a package-relative locator. Consumed by the remote MCP server and the urbicon CLI.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://codeberg.org/urbicon/ui.git",
9
+ "directory": "packages/design-content"
10
+ },
11
+ "homepage": "https://ui.urbicon.de",
12
+ "bugs": "https://codeberg.org/urbicon/ui/issues",
13
+ "keywords": [
14
+ "design-system",
15
+ "component-catalog",
16
+ "urbicon-ui",
17
+ "ai",
18
+ "llm"
19
+ ],
20
+ "type": "module",
21
+ "main": "./src/index.ts",
22
+ "types": "./src/index.ts",
23
+ "sideEffects": false,
24
+ "exports": {
25
+ ".": "./src/index.ts",
26
+ "./package.json": "./package.json"
27
+ },
28
+ "files": [
29
+ "src",
30
+ "content",
31
+ "README.md"
32
+ ],
33
+ "scripts": {
34
+ "build": "echo 'no build needed — Bun runs TypeScript directly'",
35
+ "check": "tsc --noEmit",
36
+ "test": "vitest",
37
+ "test:run": "vitest run"
38
+ },
39
+ "devDependencies": {
40
+ "typescript": "^6.0.3",
41
+ "@types/node": "^25.9.3",
42
+ "vitest": "^4.1.9"
43
+ },
44
+ "author": "Urbicon UI Team"
45
+ }
@@ -0,0 +1,78 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
2
+ import {
3
+ getCatalogPath,
4
+ getComponentLlmPath,
5
+ getContentDir,
6
+ getDesignSystemDir,
7
+ getIconsPath,
8
+ getTemplatePath
9
+ } from './content-loader.js';
10
+
11
+ describe('content-loader paths', () => {
12
+ const original = process.env.URBICON_CONTENT_DIR;
13
+
14
+ afterEach(() => {
15
+ if (original === undefined) delete process.env.URBICON_CONTENT_DIR;
16
+ else process.env.URBICON_CONTENT_DIR = original;
17
+ });
18
+
19
+ describe('getContentDir', () => {
20
+ beforeEach(() => {
21
+ delete process.env.URBICON_CONTENT_DIR;
22
+ });
23
+
24
+ it('defaults to the package-relative content/ dir', () => {
25
+ expect(getContentDir().endsWith('/content')).toBe(true);
26
+ });
27
+
28
+ it('honours the URBICON_CONTENT_DIR override', () => {
29
+ process.env.URBICON_CONTENT_DIR = '/custom/bundle';
30
+ expect(getContentDir()).toBe('/custom/bundle');
31
+ });
32
+ });
33
+
34
+ describe('derived artifact paths', () => {
35
+ beforeEach(() => {
36
+ process.env.URBICON_CONTENT_DIR = '/bundle';
37
+ });
38
+
39
+ it('resolves each artifact under the content dir', () => {
40
+ expect(getCatalogPath()).toBe('/bundle/component-catalog.json');
41
+ expect(getDesignSystemDir()).toBe('/bundle/design-system');
42
+ expect(getTemplatePath()).toBe('/bundle/guides/llms-full-template.md');
43
+ expect(getIconsPath()).toBe('/bundle/icons.json');
44
+ });
45
+ });
46
+
47
+ describe('getComponentLlmPath', () => {
48
+ beforeEach(() => {
49
+ process.env.URBICON_CONTENT_DIR = '/bundle';
50
+ });
51
+
52
+ it('resolves a valid slug under its group', () => {
53
+ expect(getComponentLlmPath('blocks/primitives', 'button')).toBe(
54
+ '/bundle/blocks/primitives/button/llm.txt'
55
+ );
56
+ });
57
+
58
+ it('accepts multi-word hyphenated slugs', () => {
59
+ expect(getComponentLlmPath('blocks/components', 'date-picker')).toBe(
60
+ '/bundle/blocks/components/date-picker/llm.txt'
61
+ );
62
+ });
63
+
64
+ it('rejects uppercase, whitespace, and edge hyphens', () => {
65
+ expect(() => getComponentLlmPath('x', 'Button')).toThrow(/Invalid component slug/);
66
+ expect(() => getComponentLlmPath('x', 'bad slug')).toThrow(/Invalid component slug/);
67
+ expect(() => getComponentLlmPath('x', '-bad')).toThrow(/Invalid component slug/);
68
+ expect(() => getComponentLlmPath('x', 'bad-')).toThrow(/Invalid component slug/);
69
+ });
70
+
71
+ it('rejects path-traversal attempts (dotted segments fail the slug guard first)', () => {
72
+ expect(() => getComponentLlmPath('x', '..')).toThrow(/Invalid component slug/);
73
+ expect(() => getComponentLlmPath('x', '../../../etc/passwd')).toThrow(
74
+ /Invalid component slug/
75
+ );
76
+ });
77
+ });
78
+ });