# CoconutJS

A collection of vanilla JavaScript Web Components for building application UIs.

Built on the native Web Components (Custom Elements) standard, CoconutJS lets you
build clean, reusable interfaces with plain JavaScript — no framework, no build
step, and a single script tag to get started.

## Installation

The package is **browser-only**. It ships prebuilt files in `dist/` that you
reference directly in your HTML (or bundle yourself); there is no Node.js/server
API.

### CDN (recommended — no install required)

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@nuvemx/coconutjs@latest/dist/coconutjs.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@nuvemx/coconutjs@latest/dist/index.js"></script>
```

### npm

For bundler users or to vendor the files locally:

```bash
npm install @nuvemx/coconutjs
```

Then reference the built outputs from `node_modules/@nuvemx/coconutjs/dist/`
(`index.js` is the ESM bundle, `index.umd.js` is the UMD bundle):

```html
<link rel="stylesheet" href="node_modules/@nuvemx/coconutjs/dist/coconutjs.css">
<script type="module" src="node_modules/@nuvemx/coconutjs/dist/index.js"></script>
```

Importing `@nuvemx/coconutjs` is a side-effect module: it automatically registers
all components with the browser's Custom Elements API (no named exports needed).

## Dependencies

The components use Bootstrap 5 component/utility classes (`btn`, `alert`, `table`,
`col-md-4`, `form-control`, …) and Boxicons `bx-*` icons. The menu navigation
uses jQuery for page switching. Load all of them alongside CoconutJS (as the
demo does):

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/boxicons@latest/css/boxicons.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@nuvemx/coconutjs@latest/dist/coconutjs.css">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@nuvemx/coconutjs@latest/dist/index.js"></script>
```

The Nunito font (referenced by the bundled CSS) can be loaded from
[Google Fonts](https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap).

## Quick Start

The simplest way to get started — a header, a sidebar menu, a page, and a footer:

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>My CoconutJS App</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/boxicons@latest/css/boxicons.min.css">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@nuvemx/coconutjs@latest/dist/coconutjs.css">
    <style>application-page:not(:defined){display:none}</style>
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js"></script>
    <script type="module" src="https://cdn.jsdelivr.net/npm/@nuvemx/coconutjs@latest/dist/index.js"></script>
</head>
<body id="root">
    <application-header logo-image="images/logo.png"></application-header>

    <application-menu label="My App">
        <application-menu-option icon="bx-home" pageId="home" label="Home" status="active"></application-menu-option>
        <application-menu-option icon="bx-info-circle" pageId="about" label="About"></application-menu-option>
    </application-menu>

    <application-page pageId="home">
        <h4>Hello, CoconutJS!</h4>
        <display-paragraph>Welcome to your first CoconutJS page.</display-paragraph>
    </application-page>

    <application-page pageId="about" display="none">
        <h4>About</h4>
        <display-note title="Tip">Built with CoconutJS Web Components.</display-note>
    </application-page>

    <application-footer brand="MyApp" copyright="MyApp Inc.">
        <a href="javascript:$('.body-content').hide();$('#home').show();">Home</a>
        <a href="javascript:$('.body-content').hide();$('#about').show();">About</a>
    </application-footer>

    <script>
        $(document).ready(function () {
            const showNavbar = (toggleId, navId, bodyId, headerId) => {
                const toggle = document.getElementById(toggleId),
                    nav = document.getElementById(navId),
                    bodypd = document.getElementById(bodyId),
                    headerpd = document.getElementById(headerId);
                if (toggle && nav && bodypd && headerpd) {
                    toggle.addEventListener('click', () => {
                        nav.classList.toggle('show');
                        toggle.classList.toggle('bx-x');
                        bodypd.classList.toggle('body-pd');
                        headerpd.classList.toggle('body-pd');
                    });
                }
            };

            showNavbar('header-toggle', 'nav-bar', 'root', 'header');

            document.addEventListener('click', (e) => {
                const link = e.target.closest('a[href^="javascript:$"]');
                if (!link) return;
                const match = (link.getAttribute('href') || '').match(/\$\('#([^']+)'\)\.show\(\)/);
                if (match && match[1]) {
                    document.querySelectorAll('.nav_link').forEach(l =>
                        l.classList.toggle('active', (l.getAttribute('href') || '').includes(match[1]))
                    );
                }
            });
        });
    </script>
</body>
</html>
```

## Prevent Flash of Unstyled Content

Add this to your `<head>` to hide page elements before their definitions are
loaded:

```html
<style>application-page:not(:defined){display:none}</style>
```

## Components

Importing `@nuvemx/coconutjs` registers all components automatically; you can
then use them in your HTML.

### Layout

| Component | Tag | Description | Key attributes |
|-----------|-----|-------------|----------------|
| `application-header` | `<application-header>` | Top header bar with toggle button and logo | `logo-image` |
| `application-main` | `<application-main>` | Wraps content in the main content area | — |
| `application-menu` | `<application-menu>` | Collapsible sidebar navigation | `label` |
| `application-menu-option` | `<application-menu-option>` | Menu navigation item; shows its `pageId` page on click | `label`, `pageId`, `icon`, `status` |
| `application-page` | `<application-page>` | Page content wrapper toggled by the menu | `pageId`, `display` |
| `application-footer` | `<application-footer>` | Footer with brand, nav links, social icons, and copyright | `brand`, `brand-description`, `copyright`, `year`, `logo` |
| `layout-grid` | `<layout-grid>` | Centered gallery grid of items with click-to-open modal | (reads `data-name`/`data-description` from children) |

### Display

| Component | Tag | Description | Key attributes |
|-----------|-----|-------------|----------------|
| `display-note` | `<display-note>` | Informational alert box | `title` |
| `display-warning` | `<display-warning>` | Warning alert box | `title` |
| `display-paragraph` | `<display-paragraph>` | Styled paragraph text | `size` (`sm`/`md`/`lg`), `muted` |
| `display-link` | `<display-link>` | Styled anchor link, optionally with icon | `href`, `target`, `icon` |
| `display-cta` | `<display-cta>` | Call-to-action button | `title`, `url`, `variant` |
| `display-image` | `<display-image>` | Responsive figure with optional caption | `src`, `alt`, `caption`, `width`, `height` |
| `display-collapsible` | `<display-collapsible>` | Click-to-toggle collapsible section | `title`, `icon` |
| `display-table` | `<display-table>` | Table from `columns`/`rows` JSON, or wraps a slot table | `columns`, `rows`, `striped`, `hover`, `bordered`, `sm` |
| `display-code` | `<display-code>` | Code block with copy-to-clipboard button | `language` |

### Inputs & Forms

| Component | Tag | Description | Key attributes |
|-----------|-----|-------------|----------------|
| `input-checkbox-field` | `<input-checkbox-field>` | Checkbox with label | `label`, `value` |
| `input-number-field` | `<input-number-field>` | Number input with validation | `label`, `value`, `min`, `max`, `step`, `placeholder`, `required` |
| `input-textarea-field` | `<input-textarea-field>` | Multi-line text input | `label`, `value`, `placeholder`, `rows`, `cols` |

## License

MIT
