Skip to content

docs: add Home page with library usage examples#241

Merged
desmondinho merged 13 commits intodevfrom
docs/showcases
Aug 20, 2025
Merged

docs: add Home page with library usage examples#241
desmondinho merged 13 commits intodevfrom
docs/showcases

Conversation

@desmondinho
Copy link
Contributor

@desmondinho desmondinho commented Aug 20, 2025

Description

Closes #128

This PR adds a Home page with examples demonstrating how different LumexUI components can be composed together.

What's been done?

  • {Change 1}
  • {Change 2}
  • ...

Checklist

  • My code follows the project's coding style and guidelines.
  • I have included inline docs for my changes, where applicable.
  • I have added, updated or removed tests according to my changes.
  • All tests are passing.
  • There's an open issue for the PR that I am making.

Additional Notes

Summary by CodeRabbit

  • New Features

    • New Docs home and layout, Theme selector and site theming service, many example pages (Usage, TeamMembers, ShareAccess, UserTable, ActivityGoal, CookieSettings, ChatSupport, Stats, Authentication, PaymentMethod), charting modules for examples, new icons (Apple, Google, Paypal, CreditCardFilled, EnvelopeFilled, PhoneFilled, Plus, Minus, SendAlt, Sparkles).
  • Improvements

    • Header/nav updates and GitHub badge with count, CDN preconnect and chart scripts, tooltip accessibility tweak (aria-expanded), improved popover overlay behavior and auto-update positioning, stronger invalid input styling, faster enter animation.
  • Bug Fixes

    • Fixed Default Ghost variant border class.

@desmondinho desmondinho linked an issue Aug 20, 2025 that may be closed by this pull request
1 task
@coderabbitai
Copy link

coderabbitai bot commented Aug 20, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds a docs Home layout and landing page with many interactive example components, introduces a DocsThemeService and ThemeSelector, extends Header parameters, integrates ApexCharts and chart JS modules, updates popover/tooltip behavior and JS positioning, adds multiple icon components, and adjusts styles and tests.

Changes

Cohort / File(s) Summary
Docs Header & Routing
docs/LumexUI.Docs.Client/Components/Header.razor, docs/LumexUI.Docs.Client/Pages/Getting Started/Overview.razor
Header exposes MaxWidth, Bordered, and Class parameters; reorders actions and updates Docs link target; Overview route changed to /docs/getting-started.
Home Layout & Landing
docs/LumexUI.Docs.Client/Components/Layouts/HomeLayout.razor, docs/LumexUI.Docs.Client/Pages/Home/Home.razor
Adds HomeLayout and new Home page using it; renders Header with specific props, footer, theme selector, hero and a grid of example components.
Theming (Docs)
docs/LumexUI.Docs.Client/Services/DocsThemeService.cs, docs/LumexUI.Docs.Client/Components/ThemeSelector.razor, docs/LumexUI.Docs.Client/Pages/Home/Examples/ExampleComponentBase.cs, docs/LumexUI.Docs.Client/Program.cs, docs/LumexUI.Docs/Program.cs, docs/LumexUI.Docs.Client/_Imports.razor
Adds a scoped DocsThemeService, ThemeSelector component, ExampleComponentBase subscribing to theme changes, DI registrations, and import.
Docs Home Examples
docs/LumexUI.Docs.Client/Pages/Home/Examples/*
Adds many example components and code-behinds (ActivityGoal, Authentication, ChatSupport, CookieSettings, PaymentMethod, ShareAccess, Stats, TeamMembers, Usage, UserTable) with UI, state, and some JS init hooks.
Docs App Assets & Charts
docs/LumexUI.Docs/Components/App.razor, docs/LumexUI.Docs/wwwroot/js/docs.js
Loads ApexCharts via CDN, reorders Prism.js, and exposes window.charts modules (activity, stats, usage) with initialize() functions; adjusts SPA navigation path handling.
Icons
src/LumexUI.Shared.Icons/*
Adds new icon components: AppleIcon, CreditCardFilledIcon, EnvelopeFilledIcon, EraserIcon, GoogleIcon, MinusIcon, PaypalIcon, PhoneFilledIcon, PlusIcon, SendAltIcon, SparklesIcon.
Popover/Tooltip (C#)
src/LumexUI/Components/Popover/LumexPopover.razor.cs, .../LumexPopoverContent.razor, .../PopoverWrapper.cs, src/LumexUI/Components/Tooltip/LumexTooltip.razor, .../LumexTooltip.razor.cs
Adds internal IsTooltip flag; renders click-to-close full-screen overlay for non-tooltips; removes wrapper onclickoutside handler and CloseAsync; adds aria-expanded placeholder and removes unused using.
Popover/JS runtime
src/LumexUI/wwwroot/js/components/popover.bundle.js, .../components/popover.js, .../elementReference.js, .../utils/dom.js
Adds observeMove/autoUpdate for repositioning, portals optional overlay, renames portalToportal, removes outside-click handler lifecycle, updates init/destroy and cleanup logic.
Styles
src/LumexUI/Styles/ColorVariants.cs, src/LumexUI/Styles/InputField.cs, src/LumexUI/Styles/_theme.css
Fixes border typo in Ghost mapping, strengthens invalid input/label styles per variant, shortens animation enter timing and easing.
Tests
tests/LumexUI.Tests/Components/Popover/PopoverTests.razor
Updated popover test to close via clicking overlay (data-popover-overlay) instead of onclickoutside event.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User
  participant ThemeSel as ThemeSelector
  participant Service as DocsThemeService
  participant Example as ExampleComponentBase

  User->>ThemeSel: select theme color
  ThemeSel->>Service: SetThemeColor(color != None)
  Service-->>Example: OnChanged event
  Example->>Example: StateHasChanged()
  Note over Example: ThemeColor reads Service.GetThemeColor()
Loading
sequenceDiagram
  autonumber
  participant User
  participant Trigger as PopoverTrigger
  participant Popover as LumexPopover
  participant Content as PopoverContent
  participant JS as popover.js/bundle

  User->>Trigger: open trigger
  Trigger->>Popover: Open()
  Popover->>Content: Render()
  alt non-tooltip
    Content->>Content: Render overlay [data-popover-overlay]
    Content->>JS: initialize(id, options)
    JS->>JS: portal(popover + overlay) & autoUpdate(start)
  else tooltip
    Content->>JS: initialize(id, options)
    JS->>JS: portal(popover) & autoUpdate(start)
  end
  User->>Content: click overlay
  Content->>Popover: CloseAsync()
  Popover->>JS: destroy()
  JS->>JS: cleanup autoUpdate
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Assessment against linked issues

Objective Addressed Explanation
Provide complex UI examples demonstrating component usage and interactions (#128)
Include advanced configurations within examples (#128)
Illustrate real-world scenarios using multiple components together (#128)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Popover JS: added autoUpdate/observeMove and internal repositioning refactor (src/.../popover.bundle.js, src/.../components/popover.js) Core runtime/positioning refactor not required by the examples objective; it changes internal popover behavior beyond sample content.
Popover C#: overlay rendering and removal of onclickoutside (src/LumexUI/Components/Popover/*) Changes core closing semantics and wrapper lifecycle unrelated to adding example pages.
Tooltip trigger aria-expanded addition (src/LumexUI/Components/Tooltip/LumexTooltip.razor) Accessibility attribute tweak not necessary for example showcase requirement.

Possibly related PRs

Poem

A rabbit hopped from doc to chart,
With icons, themes, and a clever heart.
Popovers dance and overlays gleam,
Examples stitched into the theme.
I nudged the code — a tiny art. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 72ca33e and e305615.

📒 Files selected for processing (2)
  • docs/LumexUI.Docs.Client/Pages/Home/Examples/ShareAccess.razor (1 hunks)
  • docs/LumexUI.Docs/Components/App.razor (2 hunks)
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch docs/showcases

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@desmondinho desmondinho added the 📚 Scope: Docs Improvements or additions to documentation label Aug 20, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
src/LumexUI/Styles/InputField.cs (2)

233-252: Fix trailing ! across variant-specific invalid styles; use prefix ! to ensure utilities apply

Several classes use a trailing ! (e.g., bg-danger/20!, text-danger-700!, border-danger!, after:bg-danger!), which is inconsistent with the rest of the codebase and typical Tailwind/UnoCSS important syntax. These likely won’t compile correctly.

Apply this diff to correct all affected utilities:

-                .Add( ElementClass.Empty()
-                    .Add( "bg-danger/20!" )
-                    .Add( "group-hover:bg-danger/10!" )
-                    .Add( "group-data-[focus=true]:bg-danger/10!" ), when: slot is nameof( _inputWrapper ) )
+                .Add( ElementClass.Empty()
+                    .Add( "!bg-danger/20" )
+                    .Add( "group-hover:!bg-danger/10" )
+                    .Add( "group-data-[focus=true]:!bg-danger/10" ), when: slot is nameof( _inputWrapper ) )
                 // For a better accessibility
-                .Add( "text-danger-700! placeholder:text-danger-500!", when: slot is nameof( _input ) )
-                .Add( "text-danger-700!", when: slot is nameof( _label ) ),
+                .Add( "!text-danger-700 placeholder:!text-danger-500", when: slot is nameof( _input ) )
+                .Add( "!text-danger-700", when: slot is nameof( _label ) ),
 
             InputVariant.Outlined => ElementClass.Empty()
-                .Add( ElementClass.Empty()
-                    .Add( "border-danger!" )
-                    .Add( "group-data-[focus=true]:border-danger!" ), when: slot is nameof( _inputWrapper ) ),
+                .Add( ElementClass.Empty()
+                    .Add( "!border-danger" )
+                    .Add( "group-data-[focus=true]:!border-danger" ), when: slot is nameof( _inputWrapper ) ),
 
             InputVariant.Underlined => ElementClass.Empty()
-                .Add( "after:bg-danger!", when: slot is nameof( _inputWrapper ) ),
+                .Add( "after:!bg-danger", when: slot is nameof( _inputWrapper ) ),

456-462: Broken utility string for has-[label] mt calc; extra parenthesis/bracket

The class string appears malformed:

  • has-[label]:mt-[calc(var(--text-small)) _+_8px)] has an extra ) and misplaced underscore spacing compared to the Medium/Large variants.

Apply this diff to fix the calc expression and match the pattern used below:

-                .Add( "has-[label]:mt-[calc(var(--text-small))_+_8px)]", when: slot is nameof( _base ) )
+                .Add( "has-[label]:mt-[calc(var(--text-small)_+_8px)]", when: slot is nameof( _base ) )
src/LumexUI/Styles/ColorVariants.cs (1)

75-75: Typo breaks classes: missing space in Danger/Light variant.

"bg-transparenttext-danger" should be "bg-transparent text-danger". As-is, Tailwind won’t apply either class.

Apply this diff:

-        [ThemeColor.Danger] = "bg-transparenttext-danger",
+        [ThemeColor.Danger] = "bg-transparent text-danger",
src/LumexUI/wwwroot/js/utils/dom.js (1)

25-41: Keep backward compatibility, rebuild bundles & update interop/tests

  • In src/LumexUI/wwwroot/js/utils/dom.js, simplify the signature and add a temporary alias:

    -export function portal(element, selector = undefined) {
    +export function portal(element, selector) {
        if (!(element instanceof HTMLElement)) {
            throw new Error('The provided element is not a valid HTMLElement.');
        }
    
        let destination = selector
            ? document.querySelector(selector)
            : document.body;
    
        if (!destination) {
            throw new Error(`No portal container with the given selector '${selector}' was found!`);
        }
    
        if (element.parentElement !== destination) {
            destination.appendChild(element);
        }
    }
    
    // Temporary alias for backward compatibility (remove in next major)
    export { portal as portalTo };
  • Regenerate the bundled output in
    src/LumexUI/wwwroot/js/components/popover.bundle.js
    so that internal calls to portalTo(...) become portal(...) and rely on the alias, rather than retaining the old definition.

  • Ensure the Blazor JS-interop surface still exposes portalTo: either update your interop registration to map
    window.Lumex.elementReference.portalTo = portal
    or adjust your tests to call the new name once the alias is in place.

  • Update the affected test at
    tests/LumexUI.Tests/Components/Navbar/NavbarTests.razor (around line 14)
    to reflect the alias or new function name.

  • Verify no leftover references before shipping:

    # Catch any remaining portalTo mentions
    rg -nP '\bportalTo\b' -g '!**/dist/**' -g '!**/build/**'
src/LumexUI/wwwroot/js/components/popover.bundle.js (1)

1666-1765: Bundle Out-of-Sync: uses portalTo & outside-click handler instead of overlay portaling

We ran a quick grep to compare the bundle vs. source:

  • popover.bundle.js defines and calls
    portalTo(popover)
    createOutsideClickHandler([ref, popover])destroyOutsideClickHandler
  • popover.js calls
    portal(popover)
    portal(overlay)
    • No createOutsideClickHandler or portalTo usage

This mismatch will reintroduce the old outside-click behavior and won’t portal the overlay, causing behavioral inconsistencies.

Please address as follows:

  • Rebuild popover.bundle.js from the current src/LumexUI/wwwroot/js/components/popover.js so it uses:
    • portal(popover) and portal(overlay) (in the same order as source)
    • The shared autoUpdate flow only (no standalone outside-click wiring)
  • Remove the portalTo and createOutsideClickHandler definitions/calls from the bundle
  • (If still present) Strip any debug logs related to initialization

Affected files:

  • src/LumexUI/wwwroot/js/components/popover.bundle.js
  • src/LumexUI/wwwroot/js/components/popover.js
♻️ Duplicate comments (2)
src/LumexUI.Shared.Icons/SparklesIcon.razor (1)

3-12: A11y note mirrors PlusIcon comment.

Same accessibility consideration as mentioned for PlusIcon. Please address globally via IconBase if not already handled.

src/LumexUI.Shared.Icons/MinusIcon.razor (1)

3-11: A11y note mirrors PlusIcon comment.

Same accessibility consideration as mentioned for PlusIcon. Please address globally via IconBase if not already handled.

🧹 Nitpick comments (68)
docs/LumexUI.Docs/Components/App.razor (2)

31-31: Pin ApexCharts version and add SRI.

Unpinned CDN URLs can introduce breaking changes and pose supply-chain risks. Pin to a known-good version and include an integrity/hash.

Action items:

  • Choose a specific ApexCharts version (e.g., 3.x.y that you’ve tested).
  • Add integrity and crossorigin attributes to the script tag.

Example (replace version and integrity with the correct values you validate):

<script src="https://cdn.jsdelivr.net/npm/apexcharts@<pinned-version>" integrity="<sha512-...>" crossorigin="anonymous" defer></script>

10-10: Add dns-prefetch fallback for broader hint support.

Preconnect is good. Add a dns-prefetch hint for browsers that don’t leverage preconnect as effectively.

     <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
+    <link rel="dns-prefetch" href="https://cdn.jsdelivr.net">
src/LumexUI/Styles/ColorVariants.cs (1)

5-8: Consider exposing these as IReadOnlyDictionary to prevent accidental mutation.

Static readonly reference still allows modifying dictionary contents at runtime. If these are configuration constants, prefer IReadOnlyDictionary or return new instances.

For example:

public static IReadOnlyDictionary<ThemeColor, string> Solid { get; } = new Dictionary<ThemeColor, string>
{
  // ...
};
docs/LumexUI.Docs.Client/Pages/Getting Started/Overview.razor (1)

1-1: Dual-route alias approved; add a canonical URL to avoid SEO duplication.

The page is reachable via two routes; add a canonical link so crawlers treat content as one source.

Insert after :

<HeadContent>
    <link rel="canonical" href="/docs/getting-started" />
</HeadContent>
src/LumexUI.Shared.Icons/EraserIcon.razor (1)

3-11: Add aria-hidden for decorative SVGs (accessibility).

If this icon is decorative, hide it from screen readers.

Apply this diff:

 <svg xmlns="http://www.w3.org/2000/svg"
      width="@Width"
      height="@Height"
      viewBox="0 0 24 24"
      focusable="false"
      fill="currentColor"
+     aria-hidden="true"
      @attributes="@AdditionalAttributes">

Optional: If some icons are not decorative, consider adding an optional Title/AriaLabel on IconBase and conditionally setting aria-hidden/role accordingly for all icons in one place.

src/LumexUI.Shared.Icons/SendAltIcon.razor (1)

3-11: Mirror a11y treatment used on other icons.

Same suggestion as EraserIcon: hide decorative SVGs from assistive tech.

 <svg xmlns="http://www.w3.org/2000/svg"
      width="@Width"
      height="@Height"
      viewBox="0 0 24 24"
      focusable="false"
      fill="currentColor"
+     aria-hidden="true"
      @attributes="@AdditionalAttributes">
src/LumexUI.Shared.Icons/EnvelopeFilledIcon.razor (1)

3-12: Add aria-hidden for decorative usage (a11y consistency).

Align with other icons to avoid noise in screen readers.

 <svg xmlns="http://www.w3.org/2000/svg"
      width="@Width"
      height="@Height"
      viewBox="0 0 24 24"
      focusable="false"
      fill="currentColor"
+     aria-hidden="true"
      @attributes="@AdditionalAttributes">
docs/LumexUI.Docs.Client/Components/Header.razor (1)

55-61: Make the GitHub link accessible and avoid hardcoded counts.

  • Provide a descriptive title/aria-label for the icon-only link plus number.
  • Prefer not to hardcode “294”; either pass it as a parameter or fetch at build-time so it doesn’t drift.
-        <LumexNavbarItem Class="flex">
-            <LumexLink Href="https://github.com/LumexUI/lumexui"
-                       External="@true"
-                       Class="text-foreground-500 hover:text-foreground-600 hover:opacity-100">
+        <LumexNavbarItem Class="flex">
+            <LumexLink Href="https://github.com/LumexUI/lumexui"
+                       External="@true"
+                       Class="text-foreground-500 hover:text-foreground-600 hover:opacity-100"
+                       aria-label="LumexUI on GitHub (stars)">
                 <GithubIcon Size="20" />
-                <span class="ml-1.5 text-small font-medium">294</span>
+                <span class="ml-1.5 text-small font-medium">294</span>
             </LumexLink>
         </LumexNavbarItem>

If desired, I can sketch a small build-time script to fetch the star count via the GitHub API and embed it into the docs.

docs/LumexUI.Docs.Client/Pages/Home/Examples/ShareAccess.razor (1)

29-37: Improve copy feedback for screen readers.

When only the icon changes, screen readers may miss the “copied” state. Consider keeping text (“Copied”) or add an aria-live region.

Minimal change to keep text:

-                @if( _isCopied )
-                {
-                    <CheckIcon Size="16" />
-                }
+                @if( _isCopied )
+                {
+                    <CheckIcon Size="16" />
+                    <span class="sr-only">Copied</span>
+                }
                 else
                 {
                     <text>Copy link</text>
                 }
docs/LumexUI.Docs/wwwroot/js/docs.js (9)

2-11: Path-only comparison may ignore query/hash-driven navigations — confirm intent

Using only window.location.pathname means changes in ?query or #hash won’t trigger the scroll reset. If that’s intentional to preserve scroll on filter/anchor changes, great. If not, compare the full URL parts.

Apply this minimal diff if you want to include query and hash in the comparison:

-    let currentUrl = window.location.pathname;
+    let currentUrl = window.location.pathname + window.location.search + window.location.hash;
@@
-        let newUrl = window.location.pathname;
+        let newUrl = window.location.pathname + window.location.search + window.location.hash;

6-8: Use a standards-compliant scroll behavior value

The value 'instant' is non-standard for scrollTo options. Use 'auto' for an immediate jump, or 'smooth' for animation.

-            window.scrollTo({ top: 0, left: 0, behavior: 'instant' });
+            window.scrollTo({ top: 0, left: 0, behavior: 'auto' });

12-17: Apply theme on first load, not only after enhanced navigations

Theme assignment only runs inside the enhancedload handler. On the initial page load, you can briefly render with the default theme before this kicks in.

Minimal change inside this block:

-        let currentTheme = localStorage.getItem('lumexui.theme');
-        if (currentTheme) {
-            document.documentElement.classList.remove('light', 'dark');
-            document.documentElement.classList.add(currentTheme);
-        }
+        applyThemeFromLocalStorage();

Add this helper once (outside the handler), and call it on DOMContentLoaded (see next comment):

function applyThemeFromLocalStorage() {
    const currentTheme = localStorage.getItem('lumexui.theme');
    if (currentTheme) {
        document.documentElement.classList.remove('light', 'dark');
        document.documentElement.classList.add(currentTheme);
    }
}

Would you like me to wire this up across the file in a small PR-ready patch?


36-38: Initialize theme immediately on DOMContentLoaded

Call the same helper on first load so the UI renders with the persisted theme without flashing.

 document.addEventListener('DOMContentLoaded', () => {
     interceptNavigation();
+    // Ensure theme is applied on first load too
+    if (typeof applyThemeFromLocalStorage === 'function') {
+        applyThemeFromLocalStorage();
+    }
 });

20-34: Clipboard fallback for non-secure contexts and older browsers

navigator.clipboard requires a secure context and (often) a user gesture. Provide a safe textarea fallback.

 async function copyToClipboard(elementId) {
@@
-    try {
-        await navigator.clipboard.writeText(text)
-        console.log('Text copied to clipboard');
+    try {
+        if (navigator.clipboard && window.isSecureContext) {
+            await navigator.clipboard.writeText(text);
+        } else {
+            // Fallback: temp textarea
+            const ta = document.createElement('textarea');
+            ta.value = text ?? '';
+            ta.style.position = 'fixed';
+            ta.style.top = '-10000px';
+            ta.style.opacity = '0';
+            document.body.appendChild(ta);
+            ta.focus();
+            ta.select();
+            document.execCommand('copy');
+            document.body.removeChild(ta);
+        }
+        console.log('Text copied to clipboard');
     } catch (err) {
         console.error('Error copying text:', err);
     }
 }

41-42: Consider tracking chart instances to avoid leaks and double-renders

Repeated initializations (e.g., re-render or navigation into the same example) can stack multiple charts in the same container. Store instances and destroy prior ones before re-render.

Example approach to add globally (non-diff snippet, place near charts bootstrap):

window.charts = window.charts || {};
window.charts.__instances = window.charts.__instances || {};
window.charts.__render = function(key, el, options) {
    if (!el) return;
    if (typeof ApexCharts === 'undefined') {
        console.warn('ApexCharts is not loaded');
        return;
    }
    // Destroy existing chart for this key
    const prev = window.charts.__instances[key];
    if (prev && typeof prev.destroy === 'function') prev.destroy();
    const inst = new ApexCharts(el, options);
    window.charts.__instances[key] = inst;
    inst.render();
};

Then, in each initializer, replace new ApexCharts(...) with:

const el = document.getElementById('chart-activity');
window.charts.__render('activity', el, options);

I can provide a ready-to-apply diff if you prefer this route.


43-81: Guard against missing element and unloaded ApexCharts before rendering the Activity chart

Defensive guards prevent runtime errors if the DOM element isn’t present yet or ApexCharts hasn’t loaded.

-        new ApexCharts(document.getElementById('chart-activity'), options).render();
+        const el = document.getElementById('chart-activity');
+        if (!el) return;
+        if (typeof ApexCharts === 'undefined') {
+            console.warn('ApexCharts is not loaded');
+            return;
+        }
+        new ApexCharts(el, options).render();

82-122: Same guards for the Stats chart

Mirror the safety checks for consistency.

-        new ApexCharts(document.getElementById('chart-stats'), options).render();
+        const el = document.getElementById('chart-stats');
+        if (!el) return;
+        if (typeof ApexCharts === 'undefined') {
+            console.warn('ApexCharts is not loaded');
+            return;
+        }
+        new ApexCharts(el, options).render();

123-157: Same guards for the Usage donut chart

Apply the same checks here to keep all chart modules robust.

-        new ApexCharts(document.getElementById('chart-usage'), options).render();
+        const el = document.getElementById('chart-usage');
+        if (!el) return;
+        if (typeof ApexCharts === 'undefined') {
+            console.warn('ApexCharts is not loaded');
+            return;
+        }
+        new ApexCharts(el, options).render();
src/LumexUI.Shared.Icons/PhoneFilledIcon.razor (1)

1-10: Icon component implementation looks consistent and correct

Inherits IconBase, uses currentColor, forwards attributes. Matches the pattern used across your icon set.

For accessibility:

  • If the icon is purely decorative, consider setting aria-hidden="true" by default (unless an aria-label/title is provided via AdditionalAttributes).
  • If it conveys meaning, ensure consumers pass an accessible name via aria-label or a <title> child.
src/LumexUI.Shared.Icons/PlusIcon.razor (1)

3-10: A11y: Ensure decorative icons are hidden from AT by default (or labeled when meaningful).

Please confirm whether IconBase sets sensible defaults (e.g., aria-hidden="true" for decorative usage, or role="img" with aria-label/title when used as content). If IconBase doesn’t handle this, consider standardizing accessibility semantics across icons.

Would you like me to propose a small shared approach in IconBase to centralize this?

docs/LumexUI.Docs.Client/Pages/Home/Examples/CookieSettings.razor.cs (1)

5-14: Make the styling slots field readonly to avoid accidental mutation.

The slots are constant for the component; marking it readonly communicates intent and prevents reassignment.

Apply this diff:

-	private SwitchSlots _classes = new()
+	private readonly SwitchSlots _classes = new()
 	{
 		Root = new ElementClass()
 			.Add( "flex-row-reverse" )
 			.Add( "gap-4" )
 			.Add( "justify-between" )
 	};
docs/LumexUI.Docs.Client/Pages/Home/Examples/Usage.razor.cs (2)

16-25: Use static readonly for the theme-to-CSS map and add a safe fallback accessor.

The map is immutable and shared across instances. Making it static readonly avoids per-instance allocations, and an accessor with a fallback prevents KeyNotFoundException if ThemeColor grows.

Apply this diff to make the dictionary static:

-	private readonly Dictionary<ThemeColor, string> _chartCssVariables = new()
+	private static readonly IReadOnlyDictionary<ThemeColor, string> ChartCssVariables = new Dictionary<ThemeColor, string>
 	{
 		[ThemeColor.Default] = "[--chart-1:var(--color-zinc-900)] [--chart-2:var(--color-zinc-700)] [--chart-3:var(--color-zinc-500)] [--chart-4:var(--color-zinc-300)]",
 		[ThemeColor.Primary] = "[--chart-1:var(--color-blue-900)] [--chart-2:var(--color-blue-600)] [--chart-3:var(--color-blue-400)] [--chart-4:var(--color-blue-300)]",
 		[ThemeColor.Secondary] = "[--chart-1:var(--color-violet-900)] [--chart-2:var(--color-violet-600)] [--chart-3:var(--color-violet-400)] [--chart-4:var(--color-violet-300)]",
 		[ThemeColor.Success] = "[--chart-1:var(--color-green-900)] [--chart-2:var(--color-green-600)] [--chart-3:var(--color-green-400)] [--chart-4:var(--color-green-300)]",
 		[ThemeColor.Warning] = "[--chart-1:var(--color-amber-900)] [--chart-2:var(--color-amber-600)] [--chart-3:var(--color-amber-400)] [--chart-4:var(--color-amber-300)]",
 		[ThemeColor.Danger] = "[--chart-1:var(--color-rose-900)] [--chart-2:var(--color-rose-600)] [--chart-3:var(--color-rose-400)] [--chart-4:var(--color-rose-300)]",
 		[ThemeColor.Info] = "[--chart-1:var(--color-sky-900)] [--chart-2:var(--color-sky-600)] [--chart-3:var(--color-sky-400)] [--chart-4:var(--color-sky-300)]",
 	};

Additionally, add a small accessor (use in .razor markup) to provide a safe fallback:

private string CurrentChartCssVariables =>
	ChartCssVariables.TryGetValue(ThemeColor, out var vars)
		? vars
		: ChartCssVariables[ThemeColor.Default];

In Usage.razor, bind wherever you currently consume the variables, e.g.:

<div class="usage-chart-container @CurrentChartCssVariables">
    ...
</div>

I can update the markup snippet if you paste the relevant portion of Usage.razor.


27-33: Optional: Call base.OnAfterRenderAsync for future-proofing.

Not required now (base doesn’t override), but calling it keeps the pattern resilient if ExampleComponentBase adds logic later.

Apply this diff:

 protected override async Task OnAfterRenderAsync( bool firstRender )
 {
+	await base.OnAfterRenderAsync(firstRender);
 	if( firstRender )
 	{
 		await JSRuntime.InvokeVoidAsync( "charts.usage.initialize" );
 	}
 }
src/LumexUI.Shared.Icons/CreditCardFilledIcon.razor (1)

3-9: Mark the SVG as decorative by default (add aria-hidden).

For purely presentational icons, add aria-hidden to keep them out of the accessibility tree unless explicitly labeled by consumers.

 <svg xmlns="http://www.w3.org/2000/svg"
      width="@Width"
      height="@Height"
      viewBox="0 0 24 24"
      focusable="false"
      fill="currentColor"
+     aria-hidden="true"
      @attributes="@AdditionalAttributes">

If you plan to support accessible labeling in the future, consider adding a Title/AriaLabel parameter to IconBase and toggling aria-hidden conditionally.

src/LumexUI.Shared.Icons/AppleIcon.razor (1)

1-11: Add aria-hidden to the SVG for better default a11y.

Same rationale as other presentational icons—hide from AT by default and allow consumers to override via AdditionalAttributes.

 <svg xmlns="http://www.w3.org/2000/svg"
      width="@Width"
      height="@Height"
      viewBox="0 0 24 24"
      focusable="false"
      fill="currentColor"
+     aria-hidden="true"
      @attributes="@AdditionalAttributes">
src/LumexUI.Shared.Icons/PaypalIcon.razor (1)

1-11: Default the SVG to decorative (aria-hidden).

Keeps screen readers from announcing non-informative glyphs. Consumers can pass aria-label via AdditionalAttributes when needed.

 <svg xmlns="http://www.w3.org/2000/svg"
      width="@Width"
      height="@Height"
      viewBox="0 0 24 24"
      focusable="false"
      fill="currentColor"
+     aria-hidden="true"
      @attributes="@AdditionalAttributes">
docs/LumexUI.Docs.Client/Pages/Home/Examples/Usage.razor (3)

23-30: Add an accessible label to the icon-only button.

Icon-only buttons should have an aria-label for screen readers.

                 <LumexDropdownTrigger Class="aria-expanded:*:bg-default/40">
                     <LumexButton IconOnly="@true"
                                  Size="@LumexUI.Common.Size.Small"
                                  Radius="@Radius.Full"
-                                 Variant="@Variant.Light">
+                                 Variant="@Variant.Light"
+                                 aria-label="More options">
                         <EllipsisVerticalIcon Size="16" />
                     </LumexButton>
                 </LumexDropdownTrigger>

12-19: Provide a visible or programmatic label for the select.

Given LabelPlacement is set, also provide Label to aid a11y. If you prefer a visually hidden label, your component may support a Class to hide it; otherwise a short visible label works.

-            <LumexSelect Value="@("Per day")"
+            <LumexSelect Value="@("Per day")"
+                         Label="Time range"
                          Size="@LumexUI.Common.Size.Small"
                          LabelPlacement="@LabelPlacement.Outside"
                          PopoverClasses="@(new() { Content = "min-w-fit" })">

41-43: Avoid self-closing non-void HTML elements.

Use an explicit closing tag for div to prevent HTML parsing quirks and to be consistent with standard markup.

-        <div class="h-40 @_chartCssVariables[ThemeColor]">
-            <div id="chart-usage" />
-        </div>
+        <div class="h-40 @_chartCssVariables[ThemeColor]">
+            <div id="chart-usage"></div>
+        </div>
docs/LumexUI.Docs.Client/Pages/Home/Examples/Stats.razor.cs (1)

16-25: Deduplicate chart CSS variable mappings across example components.

This mapping appears in multiple example components (e.g., Usage, Stats). Centralize it (e.g., in ExampleComponentBase or a small helper) to keep themes consistent and reduce maintenance.

Example (outside this file): expose from ExampleComponentBase

protected static readonly IReadOnlyDictionary<ThemeColor, string> ChartCssVariables =
    new Dictionary<ThemeColor, string>
    {
        [ThemeColor.Default] = "[--chart:var(--lumex-default-900)] [--chart-fill:--alpha(var(--chart)_/_5%)]",
        [ThemeColor.Primary] = "[--chart:var(--lumex-primary)] [--chart-fill:--alpha(var(--chart)_/_5%)]",
        [ThemeColor.Secondary] = "[--chart:var(--lumex-secondary)] [--chart-fill:--alpha(var(--chart)_/_5%)]",
        [ThemeColor.Success] = "[--chart:var(--lumex-success)] [--chart-fill:--alpha(var(--chart)_/_5%)]",
        [ThemeColor.Warning] = "[--chart:var(--lumex-warning)] [--chart-fill:--alpha(var(--chart)_/_5%)]",
        [ThemeColor.Danger] = "[--chart:var(--lumex-danger)] [--chart-fill:--alpha(var(--chart)_/_5%)]",
        [ThemeColor.Info] = "[--chart:var(--lumex-info)] [--chart-fill:--alpha(var(--chart)_/_5%)]",
    };

Then in each component: use ChartCssVariables[ThemeColor] in markup.

docs/LumexUI.Docs.Client/Pages/Home/Examples/Stats.razor (2)

25-27: Guard against missing ThemeColor keys when selecting chart CSS variables

Indexing _chartCssVariables directly risks a KeyNotFoundException if new theme colors are added later. Prefer a safe fallback to Default.

Apply in this file:

-        <div class="h-30 @_chartCssVariables[ThemeColor]">
+        <div class="h-30 @ChartCss">

And add this helper in Stats.razor.cs:

// In Stats.razor.cs
private string ChartCss =>
    _chartCssVariables.TryGetValue(ThemeColor, out var css) 
        ? css 
        : _chartCssVariables[ThemeColor.Default];

26-26: Prefer a non-self-closing div for clarity

Self-closing divs render fine in Razor, but using an explicit closing tag aids readability and avoids surprises with some HTML tooling.

-            <div id="chart-stats" />
+            <div id="chart-stats"></div>
docs/LumexUI.Docs.Client/Pages/Home/Examples/PaymentMethod.razor.cs (3)

8-17: Avoid KeyNotFoundException when ThemeColor changes or expands

Direct dictionary indexing with _colorMap[ThemeColor] will throw if a future theme is introduced without an entry. Use a safe accessor.

Apply in this file:

-            .Add( _colorMap[ThemeColor] ),
+            .Add( GetColorClasses() ),

Add this helper below:

private string GetColorClasses() =>
    _colorMap.TryGetValue(ThemeColor, out var classes)
        ? classes
        : _colorMap[ThemeColor.Default];

19-28: Make the color map static to avoid per-instance allocations

This map is immutable and the same for all instances. Mark it static readonly to reduce allocations.

-    private readonly Dictionary<ThemeColor, string> _colorMap = new()
+    private static readonly Dictionary<ThemeColor, string> _colorMap = new()
     {
         [ThemeColor.Default] = "bg-surface1 border-default-100 hover:bg-surface2 data-[selected=true]:border-default data-[selected=true]:bg-surface2",
         [ThemeColor.Primary] = "bg-primary/10 border-primary/15 hover:bg-primary/15 data-[selected=true]:border-primary data-[selected=true]:bg-primary/15",
         [ThemeColor.Secondary] = "bg-secondary/10 border-secondary/15 hover:bg-secondary/15 data-[selected=true]:border-secondary data-[selected=true]:bg-secondary/15",
         [ThemeColor.Success] = "bg-success/10 border-success/15 hover:bg-success/15 data-[selected=true]:border-success data-[selected=true]:bg-success/15",
-        [ThemeColor.Warning] = "bg-warning/5 border-warning/15 hover:bg-warning/15 data-[selected=true]:border-warning data-[selected=true]:bg-warning/15",
+        [ThemeColor.Warning] = "bg-warning/5 border-warning/15 hover:bg-warning/15 data-[selected=true]:border-warning data-[selected=true]:bg-warning/15",
         [ThemeColor.Danger] = "bg-danger/10 border-danger/15 hover:bg-danger/15 data-[selected=true]:border-danger data-[selected=true]:bg-danger/15",
         [ThemeColor.Info] = "bg-info/10 border-info/15 hover:bg-info/15 data-[selected=true]:border-info data-[selected=true]:bg-info/15",
     };

19-26: Inconsistent opacity for Warning vs other colors

Warning uses 5% background while others use 10%. If intentional, ignore; otherwise consider aligning for visual consistency.

docs/LumexUI.Docs.Client/Components/Layouts/HomeLayout.razor (1)

14-14: Slightly simplify year rendering

Using DateTime.UtcNow.Year avoids string formatting and is culture-agnostic.

-            &copy; @(DateTimeOffset.UtcNow.ToString( "yyyy" )) LumexUI. All rights reserved.
+            &copy; @DateTime.UtcNow.Year LumexUI. All rights reserved.
docs/LumexUI.Docs.Client/Pages/Home/Examples/CookieSettings.razor (1)

16-26: Consider binding Value for interactivity in the docs

As written, the first switch is always true and not bound; it may not reflect user interaction in the example. Bind it to a local field to demonstrate two-way binding.

-        <LumexSwitch Value="@true"
-                     Color="@ThemeColor"
-                     Classes="@_classes">
+        <LumexSwitch @bind-Value="_strictlyNecessary"
+                     Color="@ThemeColor"
+                     Classes="@_classes">

And in CookieSettings.razor.cs:

private bool _strictlyNecessary = true;
docs/LumexUI.Docs.Client/Pages/Home/Examples/TeamMembers.razor.cs (1)

5-11: Make static readonly data truly static

Roles are constants and identical for every instance. Marking them static reduces per-instance allocations.

-    private readonly Dictionary<string, string> _roles = new()
+    private static readonly Dictionary<string, string> _roles = new()
     {
         ["Viewer"] = "Can view and comment",
         ["Developer"] = "Can view, comment and edit",
         ["Billing"] = "Can view, comment and manage billing",
         ["Owner"] = "Admin-level access to all resources",
     };
docs/LumexUI.Docs.Client/Pages/Home/Examples/ExampleComponentBase.cs (1)

18-21: Use InvokeAsync in the theme-changed handler (avoid renderer thread violations) and call base.OnInitialized()

Subscribing StateHasChanged directly can trigger “called from the wrong thread” exceptions in some hosting modes. Use a local handler that dispatches via InvokeAsync, and unsubscribe the same handler in Dispose. Also call base.OnInitialized() for forward compatibility.

Apply this diff:

 protected override void OnInitialized()
 {
-		ThemeService.OnChanged += StateHasChanged;
+		base.OnInitialized();
+		ThemeService.OnChanged += OnThemeChanged;
 }
 
+private void OnThemeChanged() => InvokeAsync(StateHasChanged);
+
 void IDisposable.Dispose()
 {
-		ThemeService.OnChanged -= StateHasChanged;
+		ThemeService.OnChanged -= OnThemeChanged;
 }

Also applies to: 23-26

docs/LumexUI.Docs.Client/Pages/Home/Examples/Authentication.razor.cs (2)

7-9: [SupplyParameterFromForm] on a private non-parameter property is ineffective

In Razor components, [SupplyParameterFromForm] applies to component parameters. On a private non-[Parameter] property it does nothing (and can mislead future readers). If you’re using interactive EditForm binding, remove it; if you intend SSR form posts, make it a public [Parameter].

Option A (interactive form binding – remove the attribute):

-	[SupplyParameterFromForm]
-	private Login LoginModel { get; set; } = new();
+	private Login LoginModel { get; set; } = new();

Option B (SSR form posts – make it a parameter):

-	[SupplyParameterFromForm]
-	private Login LoginModel { get; set; } = new();
+	[Parameter, SupplyParameterFromForm]
+	public Login LoginModel { get; set; } = new();

Please confirm which flow you’re targeting (Interactive/SSR) so we can align the code-behind and markup accordingly.


12-12: Empty Submit handler — add TODO or wire up form events

If this is a stub for the docs sample, consider adding a TODO or wiring it to EditForm.OnValidSubmit to demonstrate a complete pattern.

docs/LumexUI.Docs.Client/Pages/Home/Examples/ActivityGoal.razor.cs (2)

32-38: Call base.OnAfterRenderAsync and keep firstRender logic

Minor improvement for consistency and forward compatibility: call base before your first-render JS init.

Apply this diff:

 protected override async Task OnAfterRenderAsync( bool firstRender )
 {
-	if( firstRender )
+	await base.OnAfterRenderAsync( firstRender );
+	if( firstRender )
 	{
 		await JSRuntime.InvokeVoidAsync( "charts.activity.initialize" );
 	}
 }

40-43: Clamp calories to [_minCalories, _maxCalories]

UI may disable the buttons at limits, but clamping in code-behind prevents out-of-range state if methods are called directly or if limits change.

Apply this diff:

 private void DecrementCalories() => SetCalories( -10 );
 private void IncrementCalories() => SetCalories( +10 );
-private void SetCalories( int value ) => _caloriesDay += value;
+private void SetCalories( int value )
+	=> _caloriesDay = System.Math.Clamp( _caloriesDay + value, _minCalories, _maxCalories );
docs/LumexUI.Docs.Client/Services/DocsThemeService.cs (1)

15-19: Avoid redundant notifications when the theme color doesn’t change

Early-out prevents unnecessary re-renders across all listening components.

Apply this diff:

 public void SetThemeColor( ThemeColor themeColor )
 {
-		_themeColor = themeColor;
-		NotifyThemeColorChanged();
+		if( _themeColor == themeColor )
+		{
+			return;
+		}
+		_themeColor = themeColor;
+		NotifyThemeColorChanged();
 }
 
 public ThemeColor GetThemeColor() => _themeColor;

Also applies to: 21-21

docs/LumexUI.Docs.Client/Pages/Home/Examples/PaymentMethod.razor (1)

16-38: Consider a default selection or binding for the radio group

For a smoother demo UX, preselect one option (e.g., “card”) or bind to a backing property. This also ensures themed selected styles are visible immediately.

docs/LumexUI.Docs.Client/Pages/Home/Examples/TeamMembers.razor (2)

16-19: Add @key to stabilize list rendering

Using @key improves Blazor diffing and avoids unnecessary re-renders when items update.

-        @foreach( var member in _members )
-        {
-            <div class="flex items-center justify-between gap-4">
+        @foreach( var member in _members )
+        {
+            @key member.Email
+            <div class="flex items-center justify-between gap-4">

46-55: Optional: Wire role selection to update the member’s role

Right now the dropdown is static. If you want the example to feel more interactive, handle item click to change the role (and visually indicate the current role).

I can provide a small code-behind helper like ChangeRole(Member member, string role) and attach OnClick="() => ChangeRole(member, title)" on LumexDropdownItem. Let me know if you want that implemented.

docs/LumexUI.Docs.Client/Pages/Home/Home.razor (1)

3-3: Remove unused NavigationManager injection

NavigationManager isn’t used in this component.

-@inject NavigationManager NavigationManager
docs/LumexUI.Docs.Client/Components/ThemeSelector.razor (3)

14-15: Avoid KeyNotFound if enum grows; add a safe accessor

If new ThemeColor values are added later, direct dictionary indexing could throw. Use a helper to provide a safe fallback.

-                    <span class="w-4 h-4 border border-default-900/10 rounded-full shrink-0 @_themeColorMap[color]" />
+                    <span class="w-4 h-4 border border-default-900/10 rounded-full shrink-0 @CssColorFor(color)" />
-            <span class="w-4 h-4 border border-default-900/10 rounded-full shrink-0 @_themeColorMap[color]" />
+            <span class="w-4 h-4 border border-default-900/10 rounded-full shrink-0 @CssColorFor(color)" />

Add outside the selected lines:

private string CssColorFor(ThemeColor color)
    => _themeColorMap.TryGetValue(color, out var cls) ? cls : _themeColorMap[ThemeColor.Default];

Also applies to: 22-23


4-9: Optional: Provide a visible label for accessibility

You set LabelPlacement.Outside but there’s no label. Adding one improves a11y.

 <LumexSelect TValue="ThemeColor"
              LabelPlacement="@LabelPlacement.Outside"
+             Label="Theme"
              Value="@_themeColor"
              ValueChanged="@HandleThemeChange"
              Class="max-w-40">

28-54: Initialize from service so the selector reflects the current theme

Currently _themeColor defaults to Default even if the service holds a different value. Initialize on component load.

Add outside the selected lines:

protected override void OnInitialized()
{
    _themeColor = ThemeService.GetThemeColor();
}
docs/LumexUI.Docs.Client/Pages/Home/Examples/ChatSupport.razor.cs (1)

13-18: [SupplyParameterFromForm] likely unnecessary here

For an interactive component handling input via standard bindings, the attribute isn’t needed and can be confusing.

-[SupplyParameterFromForm]
 private ChatMessage MessageToSend { get; set; } = new()
 {
     SenderId = "Me"
 };
docs/LumexUI.Docs.Client/Pages/Home/Examples/UserTable.razor (2)

73-80: Verify @OnClick:stopPropagation works on a component, not just HTML elements.

Event modifiers are guaranteed on HTML elements. On components, they only apply if the component renders the event to the root element via AdditionalAttributes. Confirm that this stops row selection toggling; otherwise, bind an explicit no-op handler with the modifier on the underlying clickable element or use the grid’s row/action column APIs if available.

If needed, wire a no-op handler to ensure the modifier compiles and takes effect:

-                    <LumexButton IconOnly="@true"
+                    <LumexButton IconOnly="@true"
                                  Size="@Size.Small"
                                  Radius="@Radius.Full"
                                  Variant="@Variant.Light"
-                                 @onclick:stopPropagation>
+                                 @onclick="() => {}"
+                                 @onclick:stopPropagation>

63-71: Guard Against Missing Status Keys in _statusMap

Indexing _statusMap[user.Status] will throw if a status isn’t in the map. To prevent runtime errors when an unknown (or null) status is encountered, update the markup to use a helper with a fallback value.

Files to update:

• docs/LumexUI.Docs.Client/Pages/Home/Examples/UserTable.razor (around line 63)
• docs/LumexUI.Docs.Client/Pages/Home/Examples/UserTable.razor.cs

Apply this diff in UserTable.razor:

-                        <LumexChip Size="@Size.Small"
-                                   Color="@_statusMap[user.Status]"
+                        <LumexChip Size="@Size.Small"
+                                   Color="@GetStatusColor(user.Status)"
                                    Variant="@ChipVariant.Dot"
                                    Class="border-none">

And add the helper to UserTable.razor.cs:

private ThemeColor GetStatusColor(string? status) =>
    status is not null && _statusMap.TryGetValue(status, out var color)
        ? color
        : ThemeColor.Default;
docs/LumexUI.Docs.Client/Pages/Home/Examples/ActivityGoal.razor (3)

18-25: Add accessible labels to icon-only buttons.

Icon-only controls should expose an aria-label or title for screen readers.

-            <LumexButton IconOnly="@true"
+            <LumexButton IconOnly="@true"
                          Disabled="@(_caloriesDay <= _minCalories)"
                          Size="@LumexUI.Common.Size.Small"
                          Radius="@Radius.Full"
                          Variant="@Variant.Light"
                          OnClick="@DecrementCalories"
-                         Class="size-7 min-w-7 border border-default-900/10">
+                         AriaLabel="Decrease daily goal"
+                         Class="size-7 min-w-7 border border-default-900/10">
                 <MinusIcon Size="16" />
             </LumexButton>

-            <LumexButton IconOnly="@true"
+            <LumexButton IconOnly="@true"
                          Disabled="@(_caloriesDay >= _maxCalories)"
                          Size="@LumexUI.Common.Size.Small"
                          Radius="@Radius.Full"
                          Variant="@Variant.Light"
                          OnClick="@IncrementCalories"
-                         Class="size-7 min-w-7 border border-default-900/10">
+                         AriaLabel="Increase daily goal"
+                         Class="size-7 min-w-7 border border-default-900/10">
                 <PlusIcon Size="16" />
             </LumexButton>

Also applies to: 32-40


18-19: Don’t rely only on Disabled; clamp in code-behind too.

Users can still trigger events via keyboard/automation, and state updates may race with UI. Clamp values in SetCalories to [_minCalories, _maxCalories].

Add this in ActivityGoal.razor.cs:

private void SetCalories(int value)
{
    _caloriesDay = Math.Clamp(value, _minCalories, _maxCalories);
}

Also applies to: 33-34


43-45: Confirm CSS variable injection target (class vs style).

The expression class="h-20 @_chartCssVariables[ThemeColor]" assumes the CSS variable payload is a Tailwind arbitrary property class (e.g., [--var:value]). If the map contains raw CSS (e.g., "--var:value"), it must be applied via style instead.

If it’s raw CSS, switch to:

-        <div class="h-20 @_chartCssVariables[ThemeColor]">
+        <div class="h-20" style="@_chartCssVariables[ThemeColor]">
docs/LumexUI.Docs.Client/Pages/Home/Examples/UserTable.razor.cs (2)

13-16: Consider InvariantCulture for predictable filtering across locales.

Using CurrentCultureIgnoreCase makes results locale-dependent. If you want consistent behavior regardless of user locale, switch to InvariantCultureIgnoreCase.

- result = result.Where( u => u.Name.Contains( _nameFilter, StringComparison.CurrentCultureIgnoreCase ) );
+ result = result.Where( u => u.Name.Contains( _nameFilter, StringComparison.InvariantCultureIgnoreCase ) );

22-30: Use IEnumerable/IReadOnlyList instead of IQueryable for in-memory data.

This data is purely in-memory and not provider-backed. Using IQueryable invites accidental expression tree pitfalls and can confuse readers. Prefer IEnumerable or IReadOnlyList.

- private readonly IQueryable<User> _users = new List<User>()
+ private readonly IReadOnlyList<User> _users = new List<User>()
   {
     // ...
- }.AsQueryable();
+ };

And return IEnumerable from FilteredUsers:

- private IQueryable<User> FilteredUsers
+ private IEnumerable<User> FilteredUsers
docs/LumexUI.Docs.Client/Pages/Home/Examples/Authentication.razor (2)

53-58: Brand spelling nit: “GitHub.”

Minor copy tweak to match the brand’s capitalization.

-            <ChildContent>Continue with Github</ChildContent>
+            <ChildContent>Continue with GitHub</ChildContent>

64-67: Make the link actionable or clarify intent.

LumexLink has no Href; it renders as non-navigable text. Provide a destination (e.g., “/signup”) or convert to a Button if it’s only illustrative.

-            <LumexLink Color="@ThemeColor"
-                       Class="@($"font-medium {(ThemeColor is ThemeColor.Default ? "text-foreground" : default)}")">
+            <LumexLink Href="/signup"
+                       Color="@ThemeColor"
+                       Class="@($"font-medium {(ThemeColor is ThemeColor.Default ? "text-foreground" : default)}")">
                 Sign Up
             </LumexLink>
docs/LumexUI.Docs.Client/Pages/Home/Examples/ChatSupport.razor (2)

85-93: Disable send on whitespace-only messages.

Length check allows messages like " ". Prefer IsNullOrWhiteSpace.

-                         Disabled="@(MessageToSend.Content?.Length == 0)"
+                         Disabled="@string.IsNullOrWhiteSpace(MessageToSend.Content)"

71-72: Optional: simplify chat message rendering by using the method group directly

The _renderMessages field is declared in ChatSupport.razor.cs (private readonly RenderFragment _renderMessages) and initialized in the constructor (_renderMessages = RenderMessages;). If you don’t need that indirection, you can remove the backing field and render via the method group:

• In docs/LumexUI.Docs.Client/Pages/Home/Examples/ChatSupport.razor (line 71), replace

-        @_renderMessages
+        @RenderMessages

• In ChatSupport.razor.cs, remove the private readonly RenderFragment _renderMessages; declaration and its assignment in the constructor.

If you prefer keeping the explicit field, no changes are required.

src/LumexUI/Components/Tooltip/LumexTooltip.razor (1)

17-18: Avoid aria-expanded on tooltip triggers; @null is a no-op and may not suppress internal attributes

  • Setting aria-expanded="@null" results in no attribute being rendered, and won’t reliably override any aria-expanded that LumexPopoverTrigger might add internally.
  • For tooltips, ARIA best practice is to use aria-describedby on the trigger pointing to the tooltip content’s id; aria-expanded is not appropriate for tooltips.

If the intent is to not render aria-expanded for tooltips, remove it here and ensure the trigger uses aria-describedby (can be wired in LumexPopoverTrigger using the content id). Apply this minimal change:

-    <LumexPopoverTrigger aria-expanded="@null"
+    <LumexPopoverTrigger

Optionally add a bUnit test to prevent regressions (outside selected lines):

[Fact]
public void TooltipTrigger_ShouldNotSetAriaExpanded()
{
    var cut = Render(@<text>
        <LumexTooltip>
            <LumexTooltipTrigger>
                <LumexButton>Hover me</LumexButton>
            </LumexTooltipTrigger>
            <LumexTooltipContent>Tip</LumexTooltipContent>
        </LumexTooltip>
    </text>);

    var trigger = cut.Find("[data-popovertarget]");
    trigger.HasAttribute("aria-expanded").Should().BeFalse();
}
src/LumexUI/wwwroot/js/elementReference.js (1)

5-5: API rename aligned; consider exporting an alias to avoid breaking downstream interop

Importing and exposing portal is consistent with the dom util rename. To avoid breaking consumers that may call elementReference.portalTo, export an alias for a deprecation period.

Apply this localized change:

 export const elementReference = {
     getScrollHeight,
-    portal
+    // Temporary alias to avoid breaking consumers during transition
+    portal,
+    portalTo: portal
 }

Also applies to: 17-18

tests/LumexUI.Tests/Components/Popover/PopoverTests.razor (1)

89-91: LGTM: test now targets the overlay close path

Clicking [data-popover-overlay] reflects the new behavior and the assertion remains valid. Optional: consider renaming the test to clarify semantics (e.g., ShouldCloseOnOverlayClick) and add a complementary test ensuring tooltips do not render the overlay.

Example additional test (outside selected lines):

[Fact]
public void Tooltip_ShouldNotRenderOverlay()
{
    var cut = Render(@<text>
        <LumexTooltip Open="@true">
            <LumexTooltipTrigger>
                <LumexButton>Open Tooltip</LumexButton>
            </LumexTooltipTrigger>
            <LumexTooltipContent>Tip</LumexTooltipContent>
        </LumexTooltip>
    </text>);

    // No overlay expected for tooltips
    cut.FindAll("[data-popover-overlay]").Count.Should().Be(0);
}
src/LumexUI/wwwroot/js/components/popover.js (1)

25-26: Overlay query is non-blocking; potential race with render

You await the popover, but overlay lookup is a synchronous query. If the overlay renders a tick later, it won’t be portaled and will remain in its original location. Consider an awaited lookup (with a bounded wait) for robustness.

Apply this diff to try portaling an overlay if/when it appears shortly after:

-        const overlay = document.querySelector(`[data-popover-overlay=${id}]`);
+        let overlay = document.querySelector(`[data-popover-overlay=${id}]`);
+        if (!overlay) {
+            try {
+                overlay = await waitForElement(`[data-popover-overlay=${id}]`);
+            } catch { /* noop: overlay is optional */ }
+        }
src/LumexUI/wwwroot/js/components/popover.bundle.js (1)

1644-1657: Debug logs in production bundle

Leftover console.log statements in the outside-click handler pollute the console.

Apply this diff:

-        console.log('hi');
         if (!isInsideAny) {
-            console.log('hi 2');
             elements.forEach(el =>
                 el?.dispatchEvent(new CustomEvent('clickoutside', { bubbles: true }))
             );
         }
...
-        console.log('destroy');

private readonly NavItem[] _navItems = new NavItem[]
{
new("/", "Docs"),
new("/docs/getting-started", "Docs"),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify updated route exists and is linked correctly.

Ensure a page is bound to “/docs/getting-started” and that any previous "/" or "/docs" routes redirect appropriately.

Run this to confirm the route and find potential stale routes:


🏁 Script executed:

#!/bin/bash
# Confirm a page exists for /docs/getting-started and inspect related pages.
rg -nP -C2 '^\s*@page\s+"?/docs/getting-started"?\s*$' --type=cshtml --type=razor
rg -nP -C2 '^\s*@page\s+"?/(docs(/getting-started)?|)$' --type=cshtml --type=razor

Length of output: 228


🏁 Script executed:

#!/bin/bash
# Confirm @page directives exist for /docs/getting-started and related routes
rg -nP -C2 '@page\s+"/docs/getting-started"' -g '*.razor' -g '*.cshtml'
rg -nP -C2 '@page\s+"/docs"'              -g '*.razor' -g '*.cshtml'
rg -nP -C2 '@page\s+"/"'                  -g '*.razor' -g '*.cshtml'

Length of output: 692


Missing /docs route redirect

  • docs/LumexUI.Docs.Client/Pages/Getting Started/Overview.razor defines
    • @page "/docs/getting-started"
    • @page "/docs/getting-started/overview"
  • No @page "/docs" endpoint was found—requests to /docs will 404 unless you add a redirect or stub page.
  • The root route (/) is still served by Home.razor.

Please add a page or redirect for /docs (for example, a Razor component with @page "/docs" that forwards to /docs/getting-started) so old links don’t break.

🤖 Prompt for AI Agents
In docs/LumexUI.Docs.Client/Components/Header.razor around line 66, the app
links to "/docs/getting-started" but there is no "/docs" route, so requests to
"/docs" 404; add a new Razor component with @page "/docs" (e.g.,
Pages/Docs/Index.razor) that immediately redirects to "/docs/getting-started"
using NavigationManager.NavigateTo("/docs/getting-started", true) or an
equivalent server-side redirect, and ensure the new component is included in the
project so legacy "/docs" links resolve.

@desmondinho desmondinho merged commit d7e0dd0 into dev Aug 20, 2025
2 of 4 checks passed
@desmondinho desmondinho deleted the docs/showcases branch August 20, 2025 18:36
desmondinho added a commit that referenced this pull request Aug 24, 2025
* feat: support Tailwind CSS v4 (#183)

* build(deps): bump TailwindMerge.NET from 0.3.0 to 1.0.0

* feat: add new CSS theme file

* feat/build: add custom targets file to improve library usability

* chore: move `Plugin` folder one level higher; remove `Scripts` folder

* feat/build: pack new theme and custom `.targets` files

* build(docs): add `Directory.Build.props` and `Directory.Build.targets`

* chore(docs): remove tailwind npm deps; use standalone CLI instead

* docs: apply `static` on theme

* refactor(theme-provider): simplify names of box-shadow css variables

* refactor(theme-provider): opacities are percentage to match `color-mix` function syntax

* chore(components): apply  `static` on theme; fix some vars

* refactor(components): drop Tailwind CSS v3 support

* feat(theme): add custom transition variables

* fix(theme): correct `default` color; add `default-foreground` color

* chore(theme): add reference for the custom transitions approach (it's not in docs afaik)

* fix: rename `shadow-sm` to `shadow-xs`

* fix: rename `rounded-sm` to `rounded-xs`

* fix: rename `rounded` to `rounded-sm`

* fix: rename `outline-none` to `outline-hidden`

* fix: rename `ring-1` to `ring`

* fix(button): add base `cursor-pointer` class

* docs: remove `children` custom variant in favor of `*`

* fix(theme): correct `enter` custom animation

* chore(components): cleanup styles

* fix(theme): add missing comma separator in custom transition vars

* docs: configure typography

* refactor(theme): simplify `scrollbar-hide` utility

* chore(theme): apply `inline` on theme

* refactor: replace `theme` function with CSS vars

* fix(components): correct scale/translate transitions

* feat(theme): update colors from hex to oklch

* docs(installation): update installation guide

* feat(theme): add leading CSS vars

* chore(docs): fix prose `<code>` tag ticks

* refactor(utils): remove hex luminance calculator

* docs(customization): update Theme and Colors pages

* docs(colors): remove 'common colors are not configurable' callout

* fix(checkbox): correct radius styles

* fix(data-grid): correct striped styles

* fix(input/select): correct label placement out transitions

* fix(input/select): correct outlined variant focus styles

* fix(input): add cursor-pointer style on the clear button

* fix(input/select): correct flat variant focus styles

* fix(docs): correct some component examples

* build(docs): adjust Tailwind standalone CLI file download for Linux

* build(docs): adjust Tailwind standalone CLI file download for Linux

* ci(deploy): try add staging env in the ci/cd

* ci(build-test): change trigger branch

* ci(deploy): update trigger branches

* ci(deploy): change env vars usage (test)

* ci: add deploy-dev.yml; revert deploy.yml

* ci(deploy): test staging

* chore(docs): nits

* chore(components): tweak styles of some components

* chore(docs): tweak some components examples

* chore: coderabbit comments

* ci: remove deploy-dev.yml

* fix(theme): remove extra shade (950) from the color scales for consistency in dark mode (#199)

* fix(theme): remove extra key (950) from the color scales for consistency in dark mode

* build(docs): explicitly set Tailwind v4.0.9

* feat(components): introduce Avatar and AvatarGroup components (#201)

* feat: add baseline implementation

* feat: add slots

* feat: add basic slots styles

* feat: add appearance params, such as `Color`, `Radius`, `Size`

* feat: add `Bordered` and `Disabled` params

* feat: add compound variants styles

* feat: apply slots styles

* docs: add baseline examples page

* feat: add `data-loaded` attribute on img

* feat: add `ShowFallback` parameter

* chore: fix compound style variants

* chore: set `showFallback` on after first render

* feat(utils): add implicit cast to string for the `ElementClass`

* feat: add LumexAvatarGroup component

* feat: take into account when LumexAvatar is rendered inside the LumexAvatarGroup

* feat: add `AvatarClasses` parameter in the avatar group component

* docs: add Avatar page

* build(docs): explicitly set Tailwind v4.0.9

* test: add tests for LumexAvatar and LumexAvatarGroup components

* chore: simplify condition for fallback render

* fix(docs): replace usages of `-foreground-950` CSS classes with `-foreground-900`

* fix(docs): remove `dark:prose-invert` CSS class until dark theme is properly configured

* feat(components): introduce Skeleton component (#202)

* feat(skeleton): add baseline implementation of the component

* feat(skeleton): add slots and styles

* feat(skeleton): add XML summaries

* fix(skeleton): return back `after` pseudo CSS classes to prevent flickering on state change

* docs(skeleton): add Skeleton page

* test(skeleton): add tests

* docs(skeleton): fix Loading example button text

* fix(navbar): add a check before toggling navbar menu on navigation (#204)

* feat(components): introduce Spinner component (#207)

* feat(spinner): add baseline implementation

* feat(spinner): add variants and styles

* feat(spinner): add slots

* docs(spinner): add Spinner page

* docs: nits

* test(spinner): add tests

* docs: map static assets

* build(docs): remove extra MSBuild target for the Tailwind prod build

* docs: revert static assets changes

* docs: update static assets usage

* Revert "docs: update static assets usage"

This reverts commit 94ae9ec.

* feat(components): introduce Chip component (#211)

* feat(chip): add baseline implementation

* feat(chip): add ChipVariant enum

* feat(chip): add appearance parameters and styles

* feat(chip): add AvatarContent parameter

* feat(chip): adjust paddings when chip has start/end content

* docs(chip): add Chip page

* feat(chip): add XML summaries

* test(chip): add tests

* chore(components): add missing XML documentation summaries

* feat(components): add new Badge component (#222)

* feat(badge): initial

* feat(badge): add badge slots

* feat(badge): add badge baseline implementation

* feat(badge): add base visual-related params

* feat(badge): add majority of badge styles

* feat(badge): add outline around badge

* feat(badge): add `Invisible` param to control badge visibility

* feat(badge): add `IsOneChar` param to make badge equilateral

* feat(badge): decrease badge dimensions if no content provided

* refactor(badge): rename `IsOneChar` param to `OneChar`

* fix(badge): use correct type for `Variant` param

* feat(badge): apply CSS classes directly to the badge slot

* fix(badge): ensure correct placement styles

* fix(badge): correct `Content` check condition

* fix(badge): allow null for content

* fix(badge): properly render Content as RenderFragment

* docs(badge): add Badge docs page

* test(badge): add tests

* test(badge): add more tests

* fix(badge): ensure `OneChar` param is taken into account

* fix(badge): fix one char switch

* chore: apply CodeRabbit suggestions

* build(deps): bump requests from 2.32.0 to 2.32.4 in /scripts (#219)

Bumps [requests](https://github.com/psf/requests) from 2.32.0 to 2.32.4.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](psf/requests@v2.32.0...v2.32.4)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* feat(components): add Tooltip component (#224)

* feat(tooltip): initial

* refactor(popover): introduce PopoverWrapper to simplify open state

* fix(popover): ensure arrow is positioned correctly

* fix(popover): ensure popover closes on trigger click if already opened

* fix(popover): position flicker

* test(popover/dropdown): adjust tests

* refactor(popover): remove LastShown meta from popover service

* feat(tooltip): add baseline implementation

* feat(tooltip): add common visual-related parameters to pass into popover

* feat(tooltip): add OpenDelay and CloseDelay params

* docs(tooltip): add Tooltip page

* feat(tooltip): pass slots to popover

* chore(popover): add full radius styles

* test(tooltip): add tests

* docs(tooltip): minor tweaks

* docs(tooltip): typo

* feat(components): add Alert component (#225)

* feat(alert): add baseline implementation

* feat(alert): add styles (may be not complete)

* feat(alert): complete styles

* feat(button): add full radius styles

* feat(alert): apply styles

* feat(alert): add close button handler

* chore(alert): complete XML docs summaries

* chore(docs): adjust background colors for preview and toolbar

* chore(components): darken text color for warning flat variant

* chore(alert): styling tweaks

* feat(docs): add Alert page

* chore(alert): add missing close-button slot attribute

* chore(alert): ensure TitleContent takes precedence over Title

* docs(alert): add callout regarding Title and TitleContent parameters usage

* test(alert): add tests

* fix(theme): add tw custom CSS class-based dark mode variant (#226)

* refactor(theme): replace C# theme config with a new CSS-first approach (#229)

* feat(theme): add light and dark theme CSS files

* refactor(components): cleanup theme provider

* refactor(theme): remove Theme directory

* test(theme): remove Theme directory

* docs(theme): remove theme config

* fix(alert): correct RenderFragment parameters usage

* chore(theme): correct theme variables

* docs(customization): replace Customization section with Theming

* test(theme-provider): remove all tests

* feat(theme): introduce a mechanism to toggle light/dark modes (#230)

* feat(theme): introduce Theme service to manage and persist theme settings (JS)

* feat(theme): introduce Theme service to manage and persist theme settings

* docs(*): rename ComponentStatus enum to PageStatus

* docs(theming): add Dark Mode page

* chore(docs): component rename

* feat(button): add new `IconOnly` parameter

* docs(button): add demo for `IconOnly` parameter

* refactor(*): remove all bundled Google Material Icons and related code (#232)

* build: add new shared icons project

* feat(icons): add base icon component

* feat(icons): add dynamic icon component

* feat(icons): add some icons

* build(deps): reference icons in components

* refactor(accordion): use new icon components

* docs(components): use new icons in Callout components

* docs(*): use new icons

* refactor(icons): add "Icon" suffix; add more icons

* docs(*): use new icons

* test(*): fix tests

* refactor(components): remove `LumexIcon` component

* docs(datagrid): formatting

* refactor(icons): remove all Google Material Icons

* refactor(icons): remove script for downloading/updating icons

* feat(components): add dark mode support (#234)

* feat(alert): add dark mode support

* feat(button): add dark mode support

* feat(chip): add dark mode support

* feat(datagrid): add dark mode support

* feat(textbox/numbox): add dark mode support

* feat(listbox): add dark mode support

* feat(menu): add dark mode support

* feat(select): add dark mode support

* feat(tabs): add dark mode support

* fix(theme): ensure default values are of correct shade in dark mode

* feat(theme): add `color-scheme` in light theme

* fix(icons): use better icons for alert component

* docs: add dark mode support + theme toggle (#235)

* docs: add dark mode support

* docs: add missing border for the preview component

* docs: remove extra border in the preview code component

* chore(badge): improve flat variant contrast in light theme

* chore(tabs): remove `EditorRequired` attribute from `Id` param

* docs: add null check and theme class cleanup to prevent issues

* docs: remove IPopoverService injection from theme toggle component

* chore(components): remove unused / redundant types

* fix(data-grid): correct outside click handler creation

* feat(popover): enable position autoUpdate

* refactor(popover): make use of popover trigger component instead of service

* feat(dropdown): introduce dropdown trigger component instead of relying on popover service

* docs(dark-mode): update theme toggle dropdown example

* docs: add Home page with library usage examples (#241)

* feat(icons): add more icons

* docs: add showcases on home page

* chore(components): adjust some styles

* docs(overview): update paths

* chore(docs): nits

* fix(components): add missing popover js parts

* chore(docs): nits

* fix(popover): use overlay to close instead of custom outside click event

* fix(tooltip): remove pressed effect from on trigger hover

* chore(showcases): complete column visibility toggling in UserTable example

* chore(showcases): adjust legend color in usage chart

* test(popover): update tests

* chore(docs): coderabbit suggestions

* chore(*): migrate to DigitalOcean app platform

* fix(*): update custom LumexUI targets to copy theme files before build

* chore(*): add missing css files in the pack

* v2.0.0-preview.4

* perf(*): optimize fonts in docs app

* fix(docs): stylesheets import ordering

* perf(docs): optimize docs CSS output

* fix(docs): correct linux tailwind executable file name

* chore(*): delete update-icons.yml

* perf(docs): enable stream rendering on all pages

* fix(docs): ensure initial theme is set

* docs(overview): update content

* docs(installation): update content

* docs(design-tokens): update content

* docs(customization): update content

* docs(dark-mode): update content

* docs(accordion): update content

* refactor(docs): replace `Callout` with `LumexAlert`

* docs(avatar): update content

* docs(components): replace `Code` component usages with HTML tag

* fix(docs): ensure ThemeSelector sets correct theme value on init

* docs(landing): make adaptive

* docs(customization): add dark mode for global theme sample

* refactor(components): remove deprecated `Root` slot

* refactor(utils): remove redundant; update access modifiers

* docs(card): update slot names

* refactor(docs): make stream rendering global

* docs(header): remove active state from links; update stars counter

* ci(*): remove deploy.yml

* ci: run build-test on PR to main

* v2.0.0

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📚 Scope: Docs Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Showcase component usage in complex UI examples

1 participant