npm package: @riesenia/fe-rui
Description: RUI - Riešenia UI Components Library with Web Components and Vue support
Latest version: 0.1.12

# fe-rui

RUI (Rshop UI) - Components Library with Web Components and Vue 3 support.

## Installation

```bash
npm install @riesenia/fe-rui
```

## Features

- **Web Components** - Framework-agnostic custom elements that work anywhere
- **Vue Components** - Native Vue 3 components with full TypeScript support
- **Utility Functions** - Helpers for overlays, scroll locking, clipboard, and more
- **Modular Imports** - Import only what you need
- **Accessibility** - ARIA attributes and keyboard navigation built-in
- **rEvent Integration** - Optional event bus for cross-component communication

## Modular Imports

Import only what you need to keep bundle size small:

```typescript
// Import everything (all components auto-register)
import { RuiToggle, WishlistPopup, checkResolution } from "@riesenia/fe-rui";

// Import only functions (no component side effects)
import { checkResolution, showOverlay, initCopyText } from "@riesenia/fe-rui/functions";

// Import only Vue components
import { WishlistPopup } from "@riesenia/fe-rui/vue";

// Import individual Web Components (kebab-case)
import "@riesenia/fe-rui/toggle";      // Registers <rui-toggle>
import "@riesenia/fe-rui/tabs";        // Registers <rui-tabs>
import "@riesenia/fe-rui/more-items";  // Registers <rui-more-items>
```

### Using @rui Alias (Recommended)

For cleaner imports, add an alias in your bundler config:

**vite.config.ts:**
```typescript
export default defineConfig({
  resolve: {
    alias: {
      "@rui": "@riesenia/fe-rui",
    }
  }
});
```

Then use shorter imports:

```typescript
import { checkResolution } from "@rui/functions";
import { WishlistPopup } from "@rui/vue";
import "@rui/toggle";
import "@rui/tabs";
import "@rui/more-items";
```

### Vue Configuration

When using `rui-*` custom elements in Vue projects:

```typescript
// vite.config.ts
vue({
  template: {
    compilerOptions: {
      isCustomElement: (tag) => tag.startsWith("rui-"),
    },
  },
})
```

## Web Components

Web Components work in any framework or vanilla JavaScript.

### Toggle

Show/hide content with trigger-based activation.

```html
<script type="module">
  import "@riesenia/fe-rui/toggle";
</script>

<button rui-toggle-trigger="my-toggle">Toggle Content</button>

<rui-toggle rui-id="my-toggle">
  <p>Hidden content here</p>
</rui-toggle>

<style>
  rui-toggle { display: none; }
  rui-toggle.is-active { display: block; }
</style>
```

### Tabs

Tab panels and accordion functionality.

```html
<script type="module">
  import "@riesenia/fe-rui/tabs";
</script>

<rui-tabs rui-id="my-tabs">
  <button rui-tab-trigger="tab1" class="is-active">Tab 1</button>
  <button rui-tab-trigger="tab2">Tab 2</button>

  <div rui-tab-target="tab1" class="is-active">Content 1</div>
  <div rui-tab-target="tab2">Content 2</div>
</rui-tabs>

<style>
  [rui-tab-target] { display: none; }
  [rui-tab-target].is-active { display: block; }
</style>
```

### MoreItems

Expand/collapse additional content.

```html
<script type="module">
  import "@riesenia/fe-rui/more-items";
</script>

<rui-more-items rui-id="my-more" data-more-text="Show more" data-less-text="Show less">
  <p>Always visible content</p>

  <div rui-more-items-target>
    <p>Hidden content that expands</p>
  </div>

  <button rui-more-items-trigger>
    <span rui-more-items-trigger-text>Show more</span>
  </button>
</rui-more-items>

<style>
  [rui-more-items-target] { display: none; }
  [rui-more-items-target].is-active { display: block; }
</style>
```

## Utility Functions

Import from `@riesenia/fe-rui/functions` (or `@rui/functions` with alias):

### Helpers

```typescript
import { checkResolution, plural, checkIphone, getScrollbarWidth, getCssVar } from "@rui/functions";

// Check if viewport matches breakpoint query
if (checkResolution("cxs;xs")) {
  // Mobile viewport
}

// Slovak plural helper
plural("položka", "položky", "položiek", count);

// Detect iPhone/iPad
if (checkIphone()) { /* ... */ }

// Get scrollbar width
const width = getScrollbarWidth();

// Get CSS custom property value
const color = getCssVar("--primary-color");
```

### Scroll Lock

```typescript
import { disableScroll, enableScroll } from "@rui/functions";

// Disable body scroll (handles iOS quirks)
disableScroll();

// Re-enable body scroll
enableScroll();
```

### Overlay

```typescript
import { showOverlay, hideOverlay, showHeaderOverlay, hideHeaderOverlay } from "@rui/functions";

// Show full-page overlay
showOverlay(ownerElement);
hideOverlay(ownerElement);

// Show header overlay (positioned below header)
showHeaderOverlay(ownerElement);
hideHeaderOverlay(ownerElement);
```

### Copy Text

```typescript
import { initCopyText, copyToClipboard } from "@rui/functions";

// Initialize click-to-copy on elements
initCopyText({
  selector: ".js-copy-text",
  onSuccess: (el, text) => console.log("Copied:", text),
});

// Or copy programmatically
await copyToClipboard("Text to copy");
```

HTML for initCopyText:
```html
<button class="js-copy-text" data-text="Text to copy" data-success-text="Copied!">
  Copy
</button>
```

## Vue Components

Vue components require Vue 3.3+.

### WishlistPopup

```typescript
import { WishlistPopup } from "@rui/vue";
```

```vue
<template>
  <WishlistPopup
    :product-id="123"
    :api-client="myApiClient"
    :endpoints="{
      fetchWishlists: '/api/wishlists',
      addToWishlist: '/api/wishlists/add'
    }"
    @product-added="handleAdded"
  />
</template>
```

## JavaScript API

All web components expose a global API:

```javascript
// Toggle
window.RUI.Toggle.open('my-toggle');
window.RUI.Toggle.close('my-toggle');
window.RUI.Toggle.toggle('my-toggle');

// Tabs
window.RUI.Tabs.activate('my-tabs', 'tab2');

// MoreItems
window.RUI.MoreItems.open('my-more');
window.RUI.MoreItems.close('my-more');
window.RUI.MoreItems.toggle('my-more');
```

Or access component instances directly:

```javascript
const toggle = document.querySelector('rui-toggle[rui-id="my-toggle"]');
toggle.open();
toggle.close();
toggle.toggle();
console.log(toggle.isActive); // boolean
```

## Events

Components dispatch CustomEvents:

```javascript
const toggle = document.querySelector('rui-toggle');

// Before events are cancelable
toggle.addEventListener('rui:toggle:beforeOpen', (e) => {
  if (someCondition) {
    e.preventDefault(); // Prevent opening
  }
});

// After events for side effects
toggle.addEventListener('rui:toggle:afterOpen', (e) => {
  console.log('Toggle opened', e.detail);
});
```

### Event Names

| Component | Events |
|-----------|--------|
| Toggle | `rui:toggle:beforeOpen`, `rui:toggle:afterOpen`, `rui:toggle:beforeClose`, `rui:toggle:afterClose` |
| Tabs | `rui:tabs:beforeChange`, `rui:tabs:afterChange` |
| MoreItems | `rui:moreitems:beforeOpen`, `rui:moreitems:afterOpen`, `rui:moreitems:beforeClose`, `rui:moreitems:afterClose` |

## CSS Classes

| Class | Description |
|-------|-------------|
| `is-active` | Applied when component/element is active |
| `is-initialized` | Applied when component is ready |

## CSS Variables

Override default styles with CSS variables:

```css
:root {
  /* Overlay */
  --rui-overlay-bg: rgba(0, 0, 0, 0.5);
  --rui-overlay-zindex: 200;
  --rui-header-overlay-zindex: 100;
}
```

## Attributes

| Attribute | Description |
|-----------|-------------|
| `rui-id` | Component identifier (required for JS API) |
| `rui-*-trigger` | Marks element as trigger |
| `rui-*-target` | Marks element as target |
| `rui-query` | Media query condition (e.g., `"cxs;xs"`) |
| `rui-overlay` | Show overlay when active |
| `data-*` | Configuration options |

## rEvent Integration

If `window.rEvent` is available, components automatically integrate:

```javascript
// Listen to events
window.rEvent.on('RuiToggle.afterOpen', (data) => {
  console.log('Toggle opened:', data.id);
});

// Trigger actions
window.rEvent.dispatch('RuiToggle.open.my-toggle');
```

## TypeScript

Full TypeScript support included:

```typescript
import { RuiToggle, RuiTabs, RuiMoreItems } from "@riesenia/fe-rui";
import { WishlistPopup } from "@riesenia/fe-rui/vue";
import type { ToggleEventDetail, TabsEventDetail, MoreItemsEventDetail } from "@riesenia/fe-rui";
```

## Browser Support

- Chrome/Edge 79+
- Firefox 63+
- Safari 14.1+

Requires native Custom Elements support (no polyfill included).

## License

MIT