@ramme-io/ui 4.0.1 → 4.1.1

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 (83) hide show
  1. package/README.md +159 -7
  2. package/dist/blocks/ai/Actions.js +2 -2
  3. package/dist/blocks/ai/PromptInput.js +6 -6
  4. package/dist/component-registry.js +389 -359
  5. package/dist/components/ai/AIChatThread/AIChatThread.js +81 -73
  6. package/dist/components/ai/ArchitectureReferenceCard/ArchitectureReferenceCard.d.ts +28 -0
  7. package/dist/components/ai/ArchitectureReferenceCard/ArchitectureReferenceCard.js +70 -0
  8. package/dist/components/ai/ArchitectureReferenceCard/index.d.ts +2 -0
  9. package/dist/components/ai/CounterpartyGraphCard/CounterpartyGraphCard.d.ts +30 -0
  10. package/dist/components/ai/CounterpartyGraphCard/CounterpartyGraphCard.js +82 -0
  11. package/dist/components/ai/CounterpartyGraphCard/index.d.ts +2 -0
  12. package/dist/components/ai/DivergenceMetricsCard/DivergenceMetricsCard.d.ts +29 -0
  13. package/dist/components/ai/DivergenceMetricsCard/DivergenceMetricsCard.js +69 -0
  14. package/dist/components/ai/DivergenceMetricsCard/index.d.ts +2 -0
  15. package/dist/components/ai/KeyInjectionOverlay.d.ts +10 -0
  16. package/dist/components/ai/KeyInjectionOverlay.js +11 -11
  17. package/dist/components/ai/NewsSummaryCard/NewsSummaryCard.js +17 -17
  18. package/dist/components/ai/StockChart/StockChart.js +4 -4
  19. package/dist/components/auth/AuthLayout.js +4 -4
  20. package/dist/components/auth/LoginPage.d.ts +22 -0
  21. package/dist/components/auth/LoginPage.js +50 -42
  22. package/dist/components/data-display/CodeBlock.d.ts +33 -7
  23. package/dist/components/data-display/CodeBlock.js +134 -41
  24. package/dist/components/data-display/Table.js +8 -8
  25. package/dist/components/feedback/EmptyState.js +9 -9
  26. package/dist/components/feedback/ToastProvider.js +4 -4
  27. package/dist/components/forms/Checkbox.js +5 -5
  28. package/dist/components/forms/ComboBox.js +2 -2
  29. package/dist/components/forms/DatePicker.js +37 -32
  30. package/dist/components/forms/FileUpload.js +39 -37
  31. package/dist/components/forms/Input.js +19 -18
  32. package/dist/components/forms/MultiSelect.js +9 -8
  33. package/dist/components/forms/Radio.js +6 -6
  34. package/dist/components/forms/SegmentedControl.d.ts +1 -1
  35. package/dist/components/forms/SegmentedControl.js +28 -11
  36. package/dist/components/forms/Select.js +9 -8
  37. package/dist/components/forms/Textarea.d.ts +13 -11
  38. package/dist/components/forms/Textarea.js +36 -16
  39. package/dist/components/forms/ToggleSwitch.js +9 -9
  40. package/dist/components/layout/AboutRamme.d.ts +8 -0
  41. package/dist/components/layout/Accordion.js +25 -32
  42. package/dist/components/layout/AppShell.js +7 -7
  43. package/dist/components/layout/Card.js +38 -21
  44. package/dist/components/layout/DetailDrawer.js +37 -38
  45. package/dist/components/layout/Drawer.js +50 -51
  46. package/dist/components/layout/List.js +9 -9
  47. package/dist/components/layout/Modal.js +5 -5
  48. package/dist/components/layout/PageHeader.js +7 -7
  49. package/dist/components/layout/SectionHeader.js +4 -4
  50. package/dist/components/layout/SettingsContainer.d.ts +12 -0
  51. package/dist/components/layout/SettingsContainer.js +30 -18
  52. package/dist/components/layout/Sheet.d.ts +58 -0
  53. package/dist/components/layout/Sheet.js +144 -0
  54. package/dist/components/layout/Sidebar.js +1 -1
  55. package/dist/components/layout/UserNav.d.ts +13 -0
  56. package/dist/components/layout/UserNav.js +17 -17
  57. package/dist/components/molecular/ConnectorOverlay.d.ts +12 -0
  58. package/dist/components/navigation/Breadcrumbs.js +8 -8
  59. package/dist/components/navigation/Menu.js +6 -6
  60. package/dist/components/navigation/MobileNav.d.ts +44 -1
  61. package/dist/components/navigation/MobileNav.js +97 -71
  62. package/dist/components/navigation/Pagination.js +46 -41
  63. package/dist/components/navigation/Stepper.js +17 -17
  64. package/dist/components/navigation/Tabs.js +18 -11
  65. package/dist/components/theme/ThemeLab.d.ts +7 -1
  66. package/dist/components/theme/ThemeLab.js +175 -154
  67. package/dist/components/ui/icon-loader.d.ts +1 -1
  68. package/dist/contexts/ThemeContext.js +111 -82
  69. package/dist/data/mockData.d.ts +0 -3
  70. package/dist/index.css +1 -1
  71. package/dist/index.d.ts +10 -0
  72. package/dist/index.js +222 -197
  73. package/dist/lib/hooks/useBodyScrollLock.d.ts +27 -0
  74. package/dist/lib/hooks/useBodyScrollLock.js +18 -0
  75. package/dist/lib/hooks/useSheetGesture.d.ts +81 -0
  76. package/dist/lib/hooks/useSheetGesture.js +70 -0
  77. package/dist/lib/theme/themeUtils.d.ts +21 -0
  78. package/dist/lib/theme/themeUtils.js +31 -17
  79. package/dist/setupTests.d.ts +1 -0
  80. package/dist/wizardManifest.js +364 -19
  81. package/package.json +10 -4
  82. package/src/wizardManifest.ts +364 -19
  83. package/tailwind.preset.js +98 -10
@@ -398,6 +398,25 @@ const e = {
398
398
  humanLabel: "AIChatThread",
399
399
  humanDescription: "A complete chat surface — message history, streaming indicator, error banner, provider/model attribution, and the composer. Strategic purpose: the presentational half of a chat feature, driven entirely by props from kernel's useRammeAI(). It holds no transport of its own, and takes a `renderMessage` override so products can add markdown or rich rendering without pulling those deps into @ramme-io/ui."
400
400
  },
401
+ {
402
+ id: "architecture-reference-card",
403
+ name: "ArchitectureReferenceCard",
404
+ version: "1.0.0",
405
+ description: "AI-generated card summarizing this platform's own data architecture — stack, data model, AI pipelines, and sentinel fleet",
406
+ tags: [
407
+ "ai",
408
+ "architecture",
409
+ "reference",
410
+ "generative-ui"
411
+ ],
412
+ category: "ai",
413
+ props: [],
414
+ importPath: "./components/ai/ArchitectureReferenceCard/ArchitectureReferenceCard",
415
+ filePath: "src/components/ai/ArchitectureReferenceCard/ArchitectureReferenceCard.tsx",
416
+ sku: "@molecule/ai/architecture-reference-card",
417
+ humanLabel: "ArchitectureReferenceCard",
418
+ humanDescription: "AI-generated card summarizing this platform's own data architecture — stack, data model, AI pipelines, and sentinel fleet"
419
+ },
401
420
  {
402
421
  id: "company-profile-card",
403
422
  name: "CompanyProfileCard",
@@ -425,6 +444,77 @@ const e = {
425
444
  humanLabel: "CompanyProfileCard",
426
445
  humanDescription: "A company summary for a ticker — sector, industry, and description — fetched on demand and cached. Strategic purpose: a generative-UI block an AI tool call can render directly into a chat thread. Surfaces its own provenance, distinguishing a live fetch from a cached or stale answer instead of presenting all three as equally fresh."
427
446
  },
447
+ {
448
+ id: "counterparty-graph-card",
449
+ name: "CounterpartyGraphCard",
450
+ version: "1.0.0",
451
+ description: "AI-generated counterparty relationship card showing suppliers, customers, partners, and competitors inferred from alternative signals",
452
+ tags: [
453
+ "ai",
454
+ "counterparty",
455
+ "graph",
456
+ "relationships",
457
+ "generative-ui"
458
+ ],
459
+ category: "ai",
460
+ props: [],
461
+ importPath: "./components/ai/CounterpartyGraphCard/CounterpartyGraphCard",
462
+ filePath: "src/components/ai/CounterpartyGraphCard/CounterpartyGraphCard.tsx",
463
+ sku: "@molecule/ai/counterparty-graph-card",
464
+ humanLabel: "CounterpartyGraphCard",
465
+ humanDescription: "AI-generated counterparty relationship card showing suppliers, customers, partners, and competitors inferred from alternative signals"
466
+ },
467
+ {
468
+ id: "divergence-metrics-card",
469
+ name: "DivergenceMetricsCard",
470
+ version: "1.0.0",
471
+ description: "AI-generated card showing operational and customer divergence scores — a signed delta between expected and observed performance",
472
+ tags: [
473
+ "ai",
474
+ "divergence",
475
+ "metrics",
476
+ "generative-ui"
477
+ ],
478
+ category: "ai",
479
+ props: [],
480
+ importPath: "./components/ai/DivergenceMetricsCard/DivergenceMetricsCard",
481
+ filePath: "src/components/ai/DivergenceMetricsCard/DivergenceMetricsCard.tsx",
482
+ sku: "@molecule/ai/divergence-metrics-card",
483
+ humanLabel: "DivergenceMetricsCard",
484
+ humanDescription: "AI-generated card showing operational and customer divergence scores — a signed delta between expected and observed performance"
485
+ },
486
+ {
487
+ id: "key-injection-overlay",
488
+ name: "KeyInjectionOverlay",
489
+ version: "1.0.0",
490
+ description: "Blocks the app and collects an AI provider key when the gateway reports one is missing or expired. Strategic purpose: the BYOK prompt, in one place, so a key request looks the same everywhere and never becomes an inline form somebody rebuilds per feature. Renders nothing unless status is 'BYOK_REQUIRED' or 'KEY_EXPIRED', so it can stay mounted at the shell level.",
491
+ tags: [
492
+ "ai",
493
+ "byok",
494
+ "overlay",
495
+ "auth",
496
+ "gateway",
497
+ "key"
498
+ ],
499
+ category: "ai",
500
+ props: [
501
+ {
502
+ name: "status",
503
+ type: "string",
504
+ description: "Gateway status. The overlay shows only for 'BYOK_REQUIRED' or 'KEY_EXPIRED'."
505
+ },
506
+ {
507
+ name: "setSessionKey",
508
+ type: "function",
509
+ description: "Receives the entered key when the form is submitted."
510
+ }
511
+ ],
512
+ importPath: "./components/ai/KeyInjectionOverlay",
513
+ filePath: "src/components/ai/KeyInjectionOverlay.tsx",
514
+ sku: "@molecule/ai/key-injection-overlay",
515
+ humanLabel: "KeyInjectionOverlay",
516
+ humanDescription: "Blocks the app and collects an AI provider key when the gateway reports one is missing or expired. Strategic purpose: the BYOK prompt, in one place, so a key request looks the same everywhere and never becomes an inline form somebody rebuilds per feature. Renders nothing unless status is 'BYOK_REQUIRED' or 'KEY_EXPIRED', so it can stay mounted at the shell level."
517
+ },
428
518
  {
429
519
  id: "live-quote-card",
430
520
  name: "LiveQuoteCard",
@@ -506,7 +596,7 @@ const e = {
506
596
  {
507
597
  id: "login-page",
508
598
  name: "LoginPage",
509
- version: "1.0.0",
599
+ version: "1.0.1",
510
600
  description: "The standard sign-in screen — email and password, with inline error and loading states already wired. Strategic purpose: a drop-in credential form so products don't rebuild one; `quickProfiles` adds one-click demo personas, which is what makes a prototype instantly explorable without real accounts.",
511
601
  tags: [
512
602
  "auth",
@@ -536,6 +626,21 @@ const e = {
536
626
  name: "quickProfiles",
537
627
  type: "Array<QuickProfile>",
538
628
  description: "Optional one-click demo identities, each `{ name, email, role }`."
629
+ },
630
+ {
631
+ name: "signupHref",
632
+ type: "string",
633
+ description: 'Where "Create one" points. Pass `null` to hide that line entirely, which is what an invite-only product wants. Defaults to `/auth/signup`.'
634
+ },
635
+ {
636
+ name: "signupLabel",
637
+ type: "string",
638
+ description: 'Text for that link. Defaults to "Create one".'
639
+ },
640
+ {
641
+ name: "forgotHref",
642
+ type: "string",
643
+ description: 'Where "Forgot?" points. Pass `null` to hide it — a product with no reset email has nothing to link to. Defaults to `#`.'
539
644
  }
540
645
  ],
541
646
  importPath: "./components/auth/LoginPage",
@@ -751,31 +856,58 @@ const e = {
751
856
  {
752
857
  id: "code-block",
753
858
  name: "CodeBlock",
754
- version: "1.0.0",
755
- description: "A component for displaying formatted and syntax-highlighted code snippets.",
859
+ version: "1.0.1",
860
+ description: "The one way to show code. Syntax-highlighted, theme-aware, with a copy button that works on touch and outside secure contexts. Use for every snippet in docs and tutorials — do not hand-roll a <pre>. Long lines scroll inside the block so the page never scrolls sideways on a phone.",
756
861
  tags: [
757
862
  "ui",
758
863
  "data-display",
759
- "code"
864
+ "code",
865
+ "docs",
866
+ "tutorial"
760
867
  ],
761
868
  category: "ui",
762
869
  props: [
763
870
  {
764
871
  name: "code",
765
872
  type: "string",
766
- description: "The string of code to display."
873
+ description: "The snippet to display. Outer blank lines are trimmed."
767
874
  },
768
875
  {
769
876
  name: "language",
770
877
  type: "string",
771
- description: "The programming language for syntax highlighting (e.g., 'tsx', 'css', 'javascript')."
878
+ description: "Prism language id — 'tsx', 'bash', 'css', 'json'. Defaults to 'tsx'."
879
+ },
880
+ {
881
+ name: "filename",
882
+ type: "string",
883
+ description: "Header label. Prefer a real path like 'src/App.tsx'; falls back to the language."
884
+ },
885
+ {
886
+ name: "showLineNumbers",
887
+ type: "boolean",
888
+ description: "Show gutter line numbers. Use when the surrounding prose cites line numbers."
889
+ },
890
+ {
891
+ name: "highlightLines",
892
+ type: "number[]",
893
+ description: '1-based lines to emphasise, for "change this line" steps.'
894
+ },
895
+ {
896
+ name: "wrap",
897
+ type: "boolean",
898
+ description: "Wrap long lines instead of scrolling them. Off by default."
899
+ },
900
+ {
901
+ name: "hideCopy",
902
+ type: "boolean",
903
+ description: "Hide the copy button, for snippets that are not meant to be run."
772
904
  }
773
905
  ],
774
906
  importPath: "./components/data-display/CodeBlock",
775
907
  filePath: "src/components/data-display/CodeBlock.tsx",
776
908
  sku: "@atom/primitive/code-block",
777
909
  humanLabel: "CodeBlock",
778
- humanDescription: "A component for displaying formatted and syntax-highlighted code snippets."
910
+ humanDescription: "The one way to show code. Syntax-highlighted, theme-aware, with a copy button that works on touch and outside secure contexts. Use for every snippet in docs and tutorials — do not hand-roll a <pre>. Long lines scroll inside the block so the page never scrolls sideways on a phone."
779
911
  },
780
912
  {
781
913
  id: "data-table",
@@ -1748,8 +1880,8 @@ const e = {
1748
1880
  {
1749
1881
  id: "segmented-control",
1750
1882
  name: "SegmentedControl",
1751
- version: "1.0.0",
1752
- description: 'A theme-aware linear toggle component. Ideal for switching between discrete modes (e.g., "Map / List").',
1883
+ version: "1.0.1",
1884
+ description: 'A theme-aware linear toggle component. Ideal for switching between discrete modes (e.g., "Map / List"). Every size clears the 24px WCAG 2.5.8 (AA) target-size minimum — xs 24px, sm ~25px, md ~36px. None reaches the 44px 2.5.5 (AAA) figure, so for a primary control on a touch screen prefer md or give the control its own 44px row; xs and sm are density sizes for pointer-driven toolbars.',
1753
1885
  tags: [
1754
1886
  "input",
1755
1887
  "toggle",
@@ -1763,7 +1895,7 @@ const e = {
1763
1895
  filePath: "src/components/forms/SegmentedControl.tsx",
1764
1896
  sku: "@atom/form/segmented-control",
1765
1897
  humanLabel: "SegmentedControl",
1766
- humanDescription: 'A theme-aware linear toggle component. Ideal for switching between discrete modes (e.g., "Map / List").'
1898
+ humanDescription: 'A theme-aware linear toggle component. Ideal for switching between discrete modes (e.g., "Map / List"). Every size clears the 24px WCAG 2.5.8 (AA) target-size minimum — xs 24px, sm ~25px, md ~36px. None reaches the 44px 2.5.5 (AAA) figure, so for a primary control on a touch screen prefer md or give the control its own 44px row; xs and sm are density sizes for pointer-driven toolbars.'
1767
1899
  },
1768
1900
  {
1769
1901
  id: "select",
@@ -1844,31 +1976,53 @@ const e = {
1844
1976
  {
1845
1977
  id: "textarea",
1846
1978
  name: "Textarea",
1847
- version: "1.0.0",
1848
- description: "A theme-aware textarea component for multi-line text input.",
1979
+ version: "1.0.1",
1980
+ description: "A theme-aware multi-line text input with label, helper text, and validation state support. Strategic purpose: the multi-line sibling of Input, styled identically so the two are indistinguishable when stacked in one form. Forwards all standard HTML textarea attributes via spread.",
1849
1981
  tags: [
1850
1982
  "form",
1851
1983
  "input",
1852
- "ui"
1984
+ "ui",
1985
+ "text",
1986
+ "multiline"
1853
1987
  ],
1854
1988
  category: "form",
1855
1989
  props: [
1856
1990
  {
1857
1991
  name: "label",
1858
1992
  type: "string",
1859
- description: "An optional label to display above the textarea."
1993
+ description: "Optional label displayed above the textarea."
1994
+ },
1995
+ {
1996
+ name: "helperText",
1997
+ type: "string",
1998
+ description: "Supporting text rendered below the textarea. Appears in destructive color when error is true."
1999
+ },
2000
+ {
2001
+ name: "error",
2002
+ type: "boolean",
2003
+ description: "If true, applies destructive border styling to indicate a validation error. Defaults to false."
2004
+ },
2005
+ {
2006
+ name: "required",
2007
+ type: "boolean",
2008
+ description: "If true, appends a required (*) indicator next to the label. Defaults to false."
2009
+ },
2010
+ {
2011
+ name: "showOptionalLabel",
2012
+ type: "boolean",
2013
+ description: "If true, appends an (optional) label when the field is not required. Defaults to false."
1860
2014
  },
1861
2015
  {
1862
2016
  name: "containerClassName",
1863
2017
  type: "string",
1864
- description: "Optional additional CSS classes for the container div."
2018
+ description: "Additional CSS classes applied to the outer container div."
1865
2019
  }
1866
2020
  ],
1867
2021
  importPath: "./components/forms/Textarea",
1868
2022
  filePath: "src/components/forms/Textarea.tsx",
1869
2023
  sku: "@atom/form/textarea",
1870
2024
  humanLabel: "Textarea",
1871
- humanDescription: "A theme-aware textarea component for multi-line text input."
2025
+ humanDescription: "A theme-aware multi-line text input with label, helper text, and validation state support. Strategic purpose: the multi-line sibling of Input, styled identically so the two are indistinguishable when stacked in one form. Forwards all standard HTML textarea attributes via spread."
1872
2026
  },
1873
2027
  {
1874
2028
  id: "toggle-switch",
@@ -2238,6 +2392,48 @@ const e = {
2238
2392
  humanLabel: "SectionHeader",
2239
2393
  humanDescription: "A simple, consistent header for organizing sections of content within a page."
2240
2394
  },
2395
+ {
2396
+ id: "connector-overlay",
2397
+ name: "ConnectorOverlay",
2398
+ version: "1.0.0",
2399
+ description: "Covers a panel while its data source is connecting, and explains itself when the connection fails. Strategic purpose: the standard treatment for a live region that has no data yet — telemetry panels, market feeds, device dashboards — so every product says the same thing about a dead socket instead of inventing a spinner. Renders nothing once status is 'connected', so it can stay mounted.",
2400
+ tags: [
2401
+ "feedback",
2402
+ "overlay",
2403
+ "connection",
2404
+ "realtime",
2405
+ "loading",
2406
+ "error"
2407
+ ],
2408
+ category: "feedback",
2409
+ props: [
2410
+ {
2411
+ name: "status",
2412
+ type: "string",
2413
+ description: "'connecting' | 'connected' | 'error'. Renders null when connected."
2414
+ },
2415
+ {
2416
+ name: "message",
2417
+ type: "ReactNode",
2418
+ description: "Replaces the default copy for the current status."
2419
+ },
2420
+ {
2421
+ name: "onRetry",
2422
+ type: "function",
2423
+ description: "Shows a retry action in the error state when provided."
2424
+ },
2425
+ {
2426
+ name: "className",
2427
+ type: "string",
2428
+ description: "Additional CSS classes."
2429
+ }
2430
+ ],
2431
+ importPath: "./components/molecular/ConnectorOverlay",
2432
+ filePath: "src/components/molecular/ConnectorOverlay.tsx",
2433
+ sku: "@molecule/feedback/connector-overlay",
2434
+ humanLabel: "ConnectorOverlay",
2435
+ humanDescription: "Covers a panel while its data source is connecting, and explains itself when the connection fails. Strategic purpose: the standard treatment for a live region that has no data yet — telemetry panels, market feeds, device dashboards — so every product says the same thing about a dead socket instead of inventing a spinner. Renders nothing once status is 'connected', so it can stay mounted."
2436
+ },
2241
2437
  {
2242
2438
  id: "data-card",
2243
2439
  name: "DataCard",
@@ -2460,8 +2656,8 @@ const e = {
2460
2656
  {
2461
2657
  id: "mobile-nav",
2462
2658
  name: "MobileNav",
2463
- version: "1.0.0",
2464
- description: 'A fixed bottom tab bar for mobile screens, providing native-feeling navigation with primary icon+label tabs and a "More" drawer for secondary links. Hidden on md: and up via Tailwind. Designed as the mobile counterpart to the desktop Sidebar.',
2659
+ version: "1.0.3",
2660
+ description: `Mobile navigation, in two shapes. 'bar' is a fixed bottom tab bar with icon+label tabs and a "More" drawer for secondary links. 'sheet' drops the bar entirely and puts every destination in a bottom drawer the host opens from its own trigger — the right choice when a mobile browser's toolbar already owns the bottom edge. Hidden on md: and up via Tailwind. The mobile counterpart to the desktop Sidebar.`,
2465
2661
  tags: [
2466
2662
  "navigation",
2467
2663
  "mobile",
@@ -2510,13 +2706,33 @@ const e = {
2510
2706
  name: "className",
2511
2707
  type: "string",
2512
2708
  description: "Additional CSS classes on the root nav bar."
2709
+ },
2710
+ {
2711
+ name: "variant",
2712
+ type: "string",
2713
+ description: `'bar' (default) renders the fixed bottom tab bar with a "More" Drawer. 'sheet' renders no bar at all and puts every destination in a Sheet — opening at 60% and growing to full as you drag or scroll it up — which the host opens itself — use it when a top header can hold the trigger, since a fixed bar and a mobile browser's own toolbar stack into ~120px of lost screen.`
2714
+ },
2715
+ {
2716
+ name: "isOpen",
2717
+ type: "boolean",
2718
+ description: "Controlled drawer state. Required by 'sheet', which has no trigger of its own; ignored by 'bar'."
2719
+ },
2720
+ {
2721
+ name: "onOpenChange",
2722
+ type: "function",
2723
+ description: "Fired when the sheet wants to close (backdrop, Escape, or an item tapped)."
2724
+ },
2725
+ {
2726
+ name: "children",
2727
+ type: "ReactNode",
2728
+ description: "Extra content rendered in the panel body after the destinations, scrolling with them. The mirror of drawerHeader; use it instead of drawerFooter when the content belongs with the list rather than pinned under it."
2513
2729
  }
2514
2730
  ],
2515
2731
  importPath: "./components/navigation/MobileNav",
2516
2732
  filePath: "src/components/navigation/MobileNav.tsx",
2517
2733
  sku: "@molecule/nav/mobile-nav",
2518
2734
  humanLabel: "MobileNav",
2519
- humanDescription: 'A fixed bottom tab bar for mobile screens, providing native-feeling navigation with primary icon+label tabs and a "More" drawer for secondary links. Hidden on md: and up via Tailwind. Designed as the mobile counterpart to the desktop Sidebar.'
2735
+ humanDescription: `Mobile navigation, in two shapes. 'bar' is a fixed bottom tab bar with icon+label tabs and a "More" drawer for secondary links. 'sheet' drops the bar entirely and puts every destination in a bottom drawer the host opens from its own trigger — the right choice when a mobile browser's toolbar already owns the bottom edge. Hidden on md: and up via Tailwind. The mobile counterpart to the desktop Sidebar.`
2520
2736
  },
2521
2737
  {
2522
2738
  id: "pagination",
@@ -2978,6 +3194,26 @@ const e = {
2978
3194
  humanLabel: "AuthLayout",
2979
3195
  humanDescription: "The centred, chrome-free frame for unauthenticated screens, rendering the matched child route via an Outlet. Strategic purpose: sign-in and sign-up must not show the app shell's sidebar or header — wrap those routes in this instead of conditionally hiding chrome inside AppShell."
2980
3196
  },
3197
+ {
3198
+ id: "about-ramme",
3199
+ name: "AboutRamme",
3200
+ version: "1.0.0",
3201
+ description: `The "About" panel for a Settings Console — what the framework is, which packages make it up, and why it is built this way. Strategic purpose: ships the explanation with the framework so every product's about screen stays accurate as the architecture moves, instead of each one carrying a copy that goes stale. Takes no props; drop it into a settings tab.`,
3202
+ tags: [
3203
+ "layout",
3204
+ "settings",
3205
+ "about",
3206
+ "documentation",
3207
+ "panel"
3208
+ ],
3209
+ category: "layout",
3210
+ props: [],
3211
+ importPath: "./components/layout/AboutRamme",
3212
+ filePath: "src/components/layout/AboutRamme.tsx",
3213
+ sku: "@chassis/layout/about-ramme",
3214
+ humanLabel: "AboutRamme",
3215
+ humanDescription: `The "About" panel for a Settings Console — what the framework is, which packages make it up, and why it is built this way. Strategic purpose: ships the explanation with the framework so every product's about screen stays accurate as the architecture moves, instead of each one carrying a copy that goes stale. Takes no props; drop it into a settings tab.`
3216
+ },
2981
3217
  {
2982
3218
  id: "accordion-item",
2983
3219
  name: "AccordionItem",
@@ -3907,6 +4143,69 @@ const e = {
3907
4143
  humanLabel: "SettingsContainer",
3908
4144
  humanDescription: "The canonical settings page arrangement, with a fixed slot per section so every app's settings read the same way. Strategic purpose: settings sprawl fast — this pins the section order and navigation so General, AI Gateway, Theme Lab, and About always live in the same place."
3909
4145
  },
4146
+ {
4147
+ id: "sheet",
4148
+ name: "Sheet",
4149
+ version: "1.0.0",
4150
+ description: "A bottom sheet that opens at a partial height and grows to full screen as you drag or scroll it up. Strategic purpose: the native-feeling surface for mobile navigation, settings and pickers — reachable by thumb, dismissed by flicking down. Use instead of Drawer when the surface is primarily touched.",
4151
+ tags: [
4152
+ "layout",
4153
+ "overlay",
4154
+ "sheet",
4155
+ "mobile",
4156
+ "touch",
4157
+ "drawer",
4158
+ "ui"
4159
+ ],
4160
+ category: "layout",
4161
+ props: [
4162
+ {
4163
+ name: "isOpen",
4164
+ type: "boolean",
4165
+ description: "Controls the open/closed state. Required."
4166
+ },
4167
+ {
4168
+ name: "onClose",
4169
+ type: "function",
4170
+ description: "Fired when the sheet requests dismissal (flick down, drag below the smallest detent, Escape, overlay tap, or the close button). Required."
4171
+ },
4172
+ {
4173
+ name: "detents",
4174
+ type: "Array<number>",
4175
+ description: "Resting heights as fractions of the viewport, ascending. Defaults to [0.6, 1] — opens at 60%, expands to full."
4176
+ },
4177
+ {
4178
+ name: "initialDetent",
4179
+ type: "number",
4180
+ description: "Index into detents to open at. Defaults to 0."
4181
+ },
4182
+ {
4183
+ name: "title",
4184
+ type: "string",
4185
+ description: "Optional title in the sticky header, beside the close button."
4186
+ },
4187
+ {
4188
+ name: "footer",
4189
+ type: "ReactNode",
4190
+ description: "Optional sticky footer, kept clear of the home indicator."
4191
+ },
4192
+ {
4193
+ name: "overlayDismiss",
4194
+ type: "boolean",
4195
+ description: "Tap the dimmed backdrop to close. Defaults to true."
4196
+ },
4197
+ {
4198
+ name: "className",
4199
+ type: "string",
4200
+ description: "Extra classes for the sheet panel."
4201
+ }
4202
+ ],
4203
+ importPath: "./components/layout/Sheet",
4204
+ filePath: "src/components/layout/Sheet.tsx",
4205
+ sku: "@chassis/layout/sheet",
4206
+ humanLabel: "Sheet",
4207
+ humanDescription: "A bottom sheet that opens at a partial height and grows to full screen as you drag or scroll it up. Strategic purpose: the native-feeling surface for mobile navigation, settings and pickers — reachable by thumb, dismissed by flicking down. Use instead of Drawer when the surface is primarily touched."
4208
+ },
3910
4209
  {
3911
4210
  id: "sidebar",
3912
4211
  name: "Sidebar",
@@ -4122,6 +4421,52 @@ const e = {
4122
4421
  sku: "@chassis/layout/user-nav",
4123
4422
  humanLabel: "UserNav",
4124
4423
  humanDescription: "The signed-in user's avatar menu — identity plus account actions. Strategic purpose: the standard account affordance for the app shell's header, with logout, settings, profile, and an optional theme toggle already wired. Compose extra entries with ButtonItem rather than rebuilding the menu."
4424
+ },
4425
+ {
4426
+ id: "button-item",
4427
+ name: "ButtonItem",
4428
+ version: "1.0.0",
4429
+ description: 'A single row inside a UserNav menu — icon, label, action. Strategic purpose: the sanctioned way to add an entry to the account menu, so extra actions match the built-in ones instead of arriving as a hand-styled button. Use `variant="destructive"` for anything that removes or signs out.',
4430
+ tags: [
4431
+ "layout",
4432
+ "navigation",
4433
+ "menu",
4434
+ "item",
4435
+ "user-nav"
4436
+ ],
4437
+ category: "layout",
4438
+ props: [
4439
+ {
4440
+ name: "icon",
4441
+ type: "string",
4442
+ description: "Lucide icon name shown before the label."
4443
+ },
4444
+ {
4445
+ name: "label",
4446
+ type: "string",
4447
+ description: "The menu entry text."
4448
+ },
4449
+ {
4450
+ name: "onClick",
4451
+ type: "function",
4452
+ description: "Called when the entry is activated."
4453
+ },
4454
+ {
4455
+ name: "variant",
4456
+ type: "string",
4457
+ description: "'default' | 'destructive'. Destructive tints the row for sign-out and delete."
4458
+ },
4459
+ {
4460
+ name: "className",
4461
+ type: "string",
4462
+ description: "Additional CSS classes."
4463
+ }
4464
+ ],
4465
+ importPath: "./components/layout/UserNav",
4466
+ filePath: "src/components/layout/UserNav.tsx",
4467
+ sku: "@chassis/layout/button-item",
4468
+ humanLabel: "ButtonItem",
4469
+ humanDescription: 'A single row inside a UserNav menu — icon, label, action. Strategic purpose: the sanctioned way to add an entry to the account menu, so extra actions match the built-in ones instead of arriving as a hand-styled button. Use `variant="destructive"` for anything that removes or signs out.'
4125
4470
  }
4126
4471
  ],
4127
4472
  utils: [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ramme-io/ui",
3
- "version": "4.0.1",
3
+ "version": "4.1.1",
4
4
  "description": "The structural component library for the Ramme Framework.",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -25,7 +25,6 @@
25
25
  "files": [
26
26
  "dist",
27
27
  "tailwind.preset.js",
28
- "index.css",
29
28
  "src/wizardManifest.ts"
30
29
  ],
31
30
  "publishConfig": {
@@ -55,13 +54,15 @@
55
54
  "tailwind-merge": "^3.3.1",
56
55
  "tippy.js": "^6.3.7",
57
56
  "zod": "^3.23.8",
58
- "@ramme-io/shared": "3.1.1"
57
+ "@ramme-io/shared": "3.1.2"
59
58
  },
60
59
  "devDependencies": {
61
60
  "@storybook/addon-links": "^10.5.9",
62
61
  "@storybook/addon-themes": "^10.5.9",
63
62
  "@storybook/react": "^10.5.9",
64
63
  "@storybook/react-vite": "^10.5.9",
64
+ "@testing-library/jest-dom": "^6.9.1",
65
+ "@testing-library/react": "^16.3.2",
65
66
  "@types/doctrine": "^0.0.9",
66
67
  "@types/node": "^20.12.12",
67
68
  "@types/react": "^18.3.23",
@@ -71,16 +72,21 @@
71
72
  "ag-grid-community": "^31.3.2",
72
73
  "ag-grid-react": "^31.3.2",
73
74
  "autoprefixer": "^10.4.19",
75
+ "axe-core": "^4.13.0",
74
76
  "doctrine": "^3.0.0",
77
+ "jsdom": "^29.0.0",
75
78
  "postcss": "^8.4.38",
76
79
  "storybook": "^10.5.9",
77
80
  "tailwindcss": "^3.4.4",
78
81
  "typescript": "^5.4.5",
79
82
  "vite": "^5.3.1",
80
- "vite-plugin-dts": "^3.9.1"
83
+ "vite-plugin-dts": "^3.9.1",
84
+ "vitest": "^2.1.9",
85
+ "vitest-axe": "^0.1.0"
81
86
  },
82
87
  "scripts": {
83
88
  "dev": "vite",
89
+ "test": "vitest run",
84
90
  "generate:manifest": "node scripts/generate-manifest.js",
85
91
  "generate:registry": "node scripts/generate-registry.js",
86
92
  "generate": "npm run generate:manifest && npm run generate:registry",