@nexus_js/ui 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,9 @@
1
+ /** @zero-bundle */
2
+ export interface AccordionProps {
3
+ title: string;
4
+ children: string;
5
+ open?: boolean;
6
+ id?: string;
7
+ }
8
+ export declare function renderAccordion(props: AccordionProps): string;
9
+ //# sourceMappingURL=accordion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accordion.d.ts","sourceRoot":"","sources":["../../src/components/accordion.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAK,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAK,OAAO,CAAC;IAClB,EAAE,CAAC,EAAO,MAAM,CAAC;CAClB;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAa7D"}
@@ -0,0 +1,14 @@
1
+ export function renderAccordion(props) {
2
+ const { title, children, open = false, id } = props;
3
+ const detailsAttrs = [
4
+ open ? 'open' : '',
5
+ id ? `id="${id}"` : '',
6
+ ].filter(Boolean).join(' ');
7
+ return `<div class="nx-accordion">
8
+ <details ${detailsAttrs}>
9
+ <summary>${title}</summary>
10
+ <div class="nx-accordion__body">${children}</div>
11
+ </details>
12
+ </div>`;
13
+ }
14
+ //# sourceMappingURL=accordion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accordion.js","sourceRoot":"","sources":["../../src/components/accordion.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,eAAe,CAAC,KAAqB;IACnD,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,GAAG,KAAK,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC;IACpD,MAAM,YAAY,GAAG;QACnB,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;QAClB,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE;KACvB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE5B,OAAO;aACI,YAAY;eACV,KAAK;sCACkB,QAAQ;;OAEvC,CAAC;AACR,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @zero-bundle — CSS :target modal. Zero JS.
3
+ *
4
+ * Usage:
5
+ * Trigger: <a href="#my-modal">Open</a>
6
+ * Close: <a href="#">Close</a>
7
+ */
8
+ export interface ModalProps {
9
+ id: string;
10
+ title: string;
11
+ children: string;
12
+ trigger?: string;
13
+ }
14
+ export declare function renderModal(props: ModalProps): string;
15
+ //# sourceMappingURL=modal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["../../src/components/modal.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAQ,MAAM,CAAC;IACjB,KAAK,EAAK,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAWrD"}
@@ -0,0 +1,12 @@
1
+ export function renderModal(props) {
2
+ const { id, title, children, trigger } = props;
3
+ const triggerHtml = trigger ? `${trigger}\n` : '';
4
+ return `${triggerHtml}<div id="${id}" class="nx-modal-overlay" role="dialog" aria-modal="true" aria-labelledby="${id}-title">
5
+ <div class="nx-modal">
6
+ <a href="#" class="nx-modal__close" aria-label="Close">×</a>
7
+ <h2 class="nx-modal__title" id="${id}-title">${title}</h2>
8
+ ${children}
9
+ </div>
10
+ </div>`;
11
+ }
12
+ //# sourceMappingURL=modal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modal.js","sourceRoot":"","sources":["../../src/components/modal.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,WAAW,CAAC,KAAiB;IAC3C,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAElD,OAAO,GAAG,WAAW,YAAY,EAAE,+EAA+E,EAAE;;;sCAGhF,EAAE,WAAW,KAAK;MAClD,QAAQ;;OAEP,CAAC;AACR,CAAC"}
@@ -0,0 +1,10 @@
1
+ /** @zero-bundle — Pure SVG progress ring. Zero JS. CSS animated. */
2
+ export interface ProgressRingProps {
3
+ value: number;
4
+ size?: number;
5
+ stroke?: number;
6
+ color?: string;
7
+ label?: string;
8
+ }
9
+ export declare function renderProgressRing(props: ProgressRingProps): string;
10
+ //# sourceMappingURL=progress-ring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-ring.d.ts","sourceRoot":"","sources":["../../src/components/progress-ring.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAK,MAAM,CAAC;IACjB,IAAI,CAAC,EAAK,MAAM,CAAC;IACjB,MAAM,CAAC,EAAG,MAAM,CAAC;IACjB,KAAK,CAAC,EAAI,MAAM,CAAC;IACjB,KAAK,CAAC,EAAI,MAAM,CAAC;CAClB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAmBnE"}
@@ -0,0 +1,20 @@
1
+ export function renderProgressRing(props) {
2
+ const { value, size = 64, stroke = 6, color = '#6366f1', label } = props;
3
+ const clamp = Math.max(0, Math.min(100, value));
4
+ const r = (size - stroke * 2) / 2;
5
+ const circ = 2 * Math.PI * r;
6
+ const offset = circ - (clamp / 100) * circ;
7
+ const center = size / 2;
8
+ return `<div class="nx-ring" style="width:${size}px;height:${size}px" role="progressbar" aria-valuenow="${clamp}" aria-valuemin="0" aria-valuemax="100">
9
+ <svg class="nx-ring__svg" width="${size}" height="${size}" viewBox="0 0 ${size} ${size}">
10
+ <circle class="nx-ring__track" cx="${center}" cy="${center}" r="${r}" stroke-width="${stroke}" />
11
+ <circle class="nx-ring__fill" cx="${center}" cy="${center}" r="${r}" stroke-width="${stroke}"
12
+ stroke="${color}"
13
+ stroke-dasharray="${circ}"
14
+ stroke-dashoffset="${offset}"
15
+ />
16
+ </svg>
17
+ <span class="nx-ring__label">${label ?? `${clamp}%`}</span>
18
+ </div>`;
19
+ }
20
+ //# sourceMappingURL=progress-ring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-ring.js","sourceRoot":"","sources":["../../src/components/progress-ring.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,kBAAkB,CAAC,KAAwB;IACzD,MAAM,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IACzE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IAChD,MAAM,CAAC,GAAQ,CAAC,IAAI,GAAG,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,IAAI,GAAK,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC;IAC3C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC;IAExB,OAAO,qCAAqC,IAAI,aAAa,IAAI,yCAAyC,KAAK;qCAC5E,IAAI,aAAa,IAAI,kBAAkB,IAAI,IAAI,IAAI;yCAC/C,MAAM,SAAS,MAAM,QAAQ,CAAC,mBAAmB,MAAM;yCACvD,MAAM,SAAS,MAAM,QAAQ,CAAC,mBAAmB,MAAM;gBAChF,KAAK;0BACK,IAAI;2BACH,MAAM;;;iCAGA,KAAK,IAAI,GAAG,KAAK,GAAG;OAC9C,CAAC;AACR,CAAC"}
@@ -0,0 +1,13 @@
1
+ /** @zero-bundle — Uses CSS :target for tab switching. Zero JS. */
2
+ export interface TabItem {
3
+ id: string;
4
+ label: string;
5
+ content: string;
6
+ default?: boolean;
7
+ }
8
+ export interface TabsProps {
9
+ tabs: TabItem[];
10
+ prefix: string;
11
+ }
12
+ export declare function renderTabs(props: TabsProps): string;
13
+ //# sourceMappingURL=tabs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../src/components/tabs.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,MAAM,WAAW,OAAO;IACtB,EAAE,EAAQ,MAAM,CAAC;IACjB,KAAK,EAAK,MAAM,CAAC;IACjB,OAAO,EAAG,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAI,OAAO,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAgBnD"}
@@ -0,0 +1,16 @@
1
+ export function renderTabs(props) {
2
+ const { tabs, prefix } = props;
3
+ const nav = tabs
4
+ .map((t) => `<a href="#${prefix}-${t.id}" class="nx-tabs__tab">${t.label}</a>`)
5
+ .join('\n ');
6
+ const panels = tabs
7
+ .map((t) => `<div id="${prefix}-${t.id}" class="nx-tabs__panel${t.default ? ' nx-tabs__panel--default' : ''}">${t.content}</div>`)
8
+ .join('\n ');
9
+ return `<div class="nx-tabs">
10
+ <nav class="nx-tabs__nav">
11
+ ${nav}
12
+ </nav>
13
+ ${panels}
14
+ </div>`;
15
+ }
16
+ //# sourceMappingURL=tabs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabs.js","sourceRoot":"","sources":["../../src/components/tabs.ts"],"names":[],"mappings":"AAaA,MAAM,UAAU,UAAU,CAAC,KAAgB;IACzC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAC/B,MAAM,GAAG,GAAG,IAAI;SACb,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,MAAM,IAAI,CAAC,CAAC,EAAE,0BAA0B,CAAC,CAAC,KAAK,MAAM,CAAC;SAC9E,IAAI,CAAC,QAAQ,CAAC,CAAC;IAElB,MAAM,MAAM,GAAG,IAAI;SAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,MAAM,IAAI,CAAC,CAAC,EAAE,0BAA0B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,QAAQ,CAAC;SACjI,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,OAAO;;MAEH,GAAG;;IAEL,MAAM;OACH,CAAC;AACR,CAAC"}
@@ -0,0 +1,8 @@
1
+ /** @zero-bundle — Pure CSS :hover tooltip. Zero JS. */
2
+ export interface TooltipProps {
3
+ text: string;
4
+ children: string;
5
+ position?: 'top' | 'bottom';
6
+ }
7
+ export declare function renderTooltip(props: TooltipProps): string;
8
+ //# sourceMappingURL=tooltip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../src/components/tooltip.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAM,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;CAC7B;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAMzD"}
@@ -0,0 +1,8 @@
1
+ export function renderTooltip(props) {
2
+ const { text, children } = props;
3
+ return `<span class="nx-tooltip" role="tooltip" aria-label="${text}">
4
+ ${children}
5
+ <span class="nx-tooltip__content" aria-hidden="true">${text}</span>
6
+ </span>`;
7
+ }
8
+ //# sourceMappingURL=tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tooltip.js","sourceRoot":"","sources":["../../src/components/tooltip.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,aAAa,CAAC,KAAmB;IAC/C,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IACjC,OAAO,uDAAuD,IAAI;IAChE,QAAQ;yDAC6C,IAAI;QACrD,CAAC;AACT,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @nexus_js/ui — Zero-Bundle Component Library
3
+ *
4
+ * Every component in this library generates pure HTML+CSS output.
5
+ * No JavaScript is shipped to the browser. The Nexus compiler detects
6
+ * the @zero-bundle annotation and replaces the component with its
7
+ * static HTML+CSS equivalent at build time.
8
+ *
9
+ * Components:
10
+ * - Accordion → <details>/<summary> with animation
11
+ * - Tabs → CSS :target pseudo-class trick
12
+ * - Toggle → <details> + CSS ::marker trick
13
+ * - Tooltip → CSS :hover + aria-label
14
+ * - Disclosure → <details> semantic variant
15
+ * - Modal → <dialog> native + :target fallback
16
+ * - ProgressRing → SVG-only animated ring
17
+ *
18
+ * Usage in .nx files:
19
+ *
20
+ * ```nx
21
+ * ---
22
+ * import { Accordion } from '@nexus_js/ui';
23
+ * ---
24
+ *
25
+ * <Accordion title="How does Nexus work?">
26
+ * It uses islands architecture...
27
+ * </Accordion>
28
+ * ```
29
+ *
30
+ * The compiler replaces this with the CSS-only HTML at build time.
31
+ * Zero JS. Zero hydration. Works even with JavaScript disabled.
32
+ */
33
+ export { renderAccordion, type AccordionProps } from './components/accordion.js';
34
+ export { renderTabs, type TabsProps } from './components/tabs.js';
35
+ export { renderTooltip, type TooltipProps } from './components/tooltip.js';
36
+ export { renderModal, type ModalProps } from './components/modal.js';
37
+ export { renderProgressRing, type ProgressRingProps } from './components/progress-ring.js';
38
+ /** @zero-bundle annotation marker — used by the Nexus compiler. */
39
+ export declare const ZERO_BUNDLE_MARKER = "__nexus_zero_bundle__";
40
+ /**
41
+ * Injects the Zero-Bundle stylesheet into a page's <head>.
42
+ * Called automatically by the renderer when @nexus_js/ui components are detected.
43
+ */
44
+ export declare function getZeroBundleCSS(): string;
45
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,eAAe,EAAE,KAAK,cAAc,EAAE,MAAQ,2BAA2B,CAAC;AACnF,OAAO,EAAE,UAAU,EAAE,KAAK,SAAS,EAAE,MAAmB,sBAAsB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,KAAK,YAAY,EAAE,MAAa,yBAAyB,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,KAAK,UAAU,EAAE,MAAiB,uBAAuB,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAE3F,mEAAmE;AACnE,eAAO,MAAM,kBAAkB,0BAA0B,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAqFzC"}
@@ -30,22 +30,19 @@
30
30
  * The compiler replaces this with the CSS-only HTML at build time.
31
31
  * Zero JS. Zero hydration. Works even with JavaScript disabled.
32
32
  */
33
-
34
- export { renderAccordion, type AccordionProps } from './components/accordion.js';
35
- export { renderTabs, type TabsProps } from './components/tabs.js';
36
- export { renderTooltip, type TooltipProps } from './components/tooltip.js';
37
- export { renderModal, type ModalProps } from './components/modal.js';
38
- export { renderProgressRing, type ProgressRingProps } from './components/progress-ring.js';
39
-
33
+ export { renderAccordion } from './components/accordion.js';
34
+ export { renderTabs } from './components/tabs.js';
35
+ export { renderTooltip } from './components/tooltip.js';
36
+ export { renderModal } from './components/modal.js';
37
+ export { renderProgressRing } from './components/progress-ring.js';
40
38
  /** @zero-bundle annotation marker — used by the Nexus compiler. */
41
39
  export const ZERO_BUNDLE_MARKER = '__nexus_zero_bundle__';
42
-
43
40
  /**
44
41
  * Injects the Zero-Bundle stylesheet into a page's <head>.
45
42
  * Called automatically by the renderer when @nexus_js/ui components are detected.
46
43
  */
47
- export function getZeroBundleCSS(): string {
48
- return `
44
+ export function getZeroBundleCSS() {
45
+ return `
49
46
  /* @nexus_js/ui — Zero-Bundle Component Styles */
50
47
  @layer nexus.ui {
51
48
 
@@ -130,3 +127,4 @@ export function getZeroBundleCSS(): string {
130
127
 
131
128
  }`;
132
129
  }
130
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,eAAe,EAAuB,MAAQ,2BAA2B,CAAC;AACnF,OAAO,EAAE,UAAU,EAAkB,MAAmB,sBAAsB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAqB,MAAa,yBAAyB,CAAC;AAClF,OAAO,EAAE,WAAW,EAAmB,MAAiB,uBAAuB,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAA0B,MAAM,+BAA+B,CAAC;AAE3F,mEAAmE;AACnE,MAAM,CAAC,MAAM,kBAAkB,GAAG,uBAAuB,CAAC;AAE1D;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmFP,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@nexus_js/ui",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "Nexus Zero-Bundle UI — CSS-only interactive components with 0.0KB of JavaScript",
5
5
  "type": "module",
6
- "main": "./src/index.ts",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
7
8
  "exports": {
8
- ".": "./src/index.ts",
9
- "./styles": "./src/styles.css"
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
10
13
  },
11
14
  "keywords": [
12
15
  "nexus",
@@ -33,12 +36,21 @@
33
36
  "bugs": {
34
37
  "url": "https://github.com/bierfor/nexus/issues"
35
38
  },
39
+ "devDependencies": {
40
+ "@types/node": "^22.0.0",
41
+ "typescript": "^5.5.0"
42
+ },
36
43
  "files": [
37
- "src",
44
+ "dist",
38
45
  "README.md"
39
46
  ],
40
47
  "publishConfig": {
41
48
  "access": "public",
42
49
  "registry": "https://registry.npmjs.org/"
50
+ },
51
+ "scripts": {
52
+ "build": "tsc -p tsconfig.json",
53
+ "dev": "tsc -p tsconfig.json --watch",
54
+ "clean": "rm -rf dist"
43
55
  }
44
56
  }
@@ -1,22 +0,0 @@
1
- /** @zero-bundle */
2
- export interface AccordionProps {
3
- title: string;
4
- children: string; // raw HTML content
5
- open?: boolean;
6
- id?: string;
7
- }
8
-
9
- export function renderAccordion(props: AccordionProps): string {
10
- const { title, children, open = false, id } = props;
11
- const detailsAttrs = [
12
- open ? 'open' : '',
13
- id ? `id="${id}"` : '',
14
- ].filter(Boolean).join(' ');
15
-
16
- return `<div class="nx-accordion">
17
- <details ${detailsAttrs}>
18
- <summary>${title}</summary>
19
- <div class="nx-accordion__body">${children}</div>
20
- </details>
21
- </div>`;
22
- }
@@ -1,26 +0,0 @@
1
- /**
2
- * @zero-bundle — CSS :target modal. Zero JS.
3
- *
4
- * Usage:
5
- * Trigger: <a href="#my-modal">Open</a>
6
- * Close: <a href="#">Close</a>
7
- */
8
- export interface ModalProps {
9
- id: string;
10
- title: string;
11
- children: string; // raw HTML body
12
- trigger?: string; // optional trigger button HTML to prepend
13
- }
14
-
15
- export function renderModal(props: ModalProps): string {
16
- const { id, title, children, trigger } = props;
17
- const triggerHtml = trigger ? `${trigger}\n` : '';
18
-
19
- return `${triggerHtml}<div id="${id}" class="nx-modal-overlay" role="dialog" aria-modal="true" aria-labelledby="${id}-title">
20
- <div class="nx-modal">
21
- <a href="#" class="nx-modal__close" aria-label="Close">×</a>
22
- <h2 class="nx-modal__title" id="${id}-title">${title}</h2>
23
- ${children}
24
- </div>
25
- </div>`;
26
- }
@@ -1,29 +0,0 @@
1
- /** @zero-bundle — Pure SVG progress ring. Zero JS. CSS animated. */
2
- export interface ProgressRingProps {
3
- value: number; // 0–100
4
- size?: number; // px, default 64
5
- stroke?: number; // stroke width, default 6
6
- color?: string; // CSS color, default #6366f1
7
- label?: string; // center text override (default: value%)
8
- }
9
-
10
- export function renderProgressRing(props: ProgressRingProps): string {
11
- const { value, size = 64, stroke = 6, color = '#6366f1', label } = props;
12
- const clamp = Math.max(0, Math.min(100, value));
13
- const r = (size - stroke * 2) / 2;
14
- const circ = 2 * Math.PI * r;
15
- const offset = circ - (clamp / 100) * circ;
16
- const center = size / 2;
17
-
18
- return `<div class="nx-ring" style="width:${size}px;height:${size}px" role="progressbar" aria-valuenow="${clamp}" aria-valuemin="0" aria-valuemax="100">
19
- <svg class="nx-ring__svg" width="${size}" height="${size}" viewBox="0 0 ${size} ${size}">
20
- <circle class="nx-ring__track" cx="${center}" cy="${center}" r="${r}" stroke-width="${stroke}" />
21
- <circle class="nx-ring__fill" cx="${center}" cy="${center}" r="${r}" stroke-width="${stroke}"
22
- stroke="${color}"
23
- stroke-dasharray="${circ}"
24
- stroke-dashoffset="${offset}"
25
- />
26
- </svg>
27
- <span class="nx-ring__label">${label ?? `${clamp}%`}</span>
28
- </div>`;
29
- }
@@ -1,30 +0,0 @@
1
- /** @zero-bundle — Uses CSS :target for tab switching. Zero JS. */
2
- export interface TabItem {
3
- id: string;
4
- label: string;
5
- content: string; // raw HTML
6
- default?: boolean;
7
- }
8
-
9
- export interface TabsProps {
10
- tabs: TabItem[];
11
- prefix: string; // unique prefix to avoid ID collisions on the page
12
- }
13
-
14
- export function renderTabs(props: TabsProps): string {
15
- const { tabs, prefix } = props;
16
- const nav = tabs
17
- .map((t) => `<a href="#${prefix}-${t.id}" class="nx-tabs__tab">${t.label}</a>`)
18
- .join('\n ');
19
-
20
- const panels = tabs
21
- .map((t) => `<div id="${prefix}-${t.id}" class="nx-tabs__panel${t.default ? ' nx-tabs__panel--default' : ''}">${t.content}</div>`)
22
- .join('\n ');
23
-
24
- return `<div class="nx-tabs">
25
- <nav class="nx-tabs__nav">
26
- ${nav}
27
- </nav>
28
- ${panels}
29
- </div>`;
30
- }
@@ -1,14 +0,0 @@
1
- /** @zero-bundle — Pure CSS :hover tooltip. Zero JS. */
2
- export interface TooltipProps {
3
- text: string; // tooltip label
4
- children: string; // trigger element (raw HTML)
5
- position?: 'top' | 'bottom';
6
- }
7
-
8
- export function renderTooltip(props: TooltipProps): string {
9
- const { text, children } = props;
10
- return `<span class="nx-tooltip" role="tooltip" aria-label="${text}">
11
- ${children}
12
- <span class="nx-tooltip__content" aria-hidden="true">${text}</span>
13
- </span>`;
14
- }