@iyulab/u-widgets 0.5.0 → 0.6.0

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.
package/README.md CHANGED
@@ -88,6 +88,46 @@ AI assistants can use u-widgets via [MCP server](docs/mcp-server.md):
88
88
  npx @iyulab/u-widgets-mcp
89
89
  ```
90
90
 
91
+ ## Framework Integration
92
+
93
+ u-widgets is a browser-only Web Component library — it requires DOM APIs (`customElements`, `HTMLElement`) and cannot run in Node.js or server-side environments.
94
+
95
+ ### Next.js (App Router)
96
+
97
+ Create a client-side wrapper component:
98
+
99
+ ```tsx
100
+ // components/widget.tsx
101
+ "use client";
102
+ import "@iyulab/u-widgets";
103
+
104
+ export function Widget({ spec }: { spec: object }) {
105
+ return <u-widget spec={JSON.stringify(spec)} />;
106
+ }
107
+ ```
108
+
109
+ Use the wrapper from Server Components:
110
+
111
+ ```tsx
112
+ // app/dashboard/page.tsx
113
+ import { Widget } from "@/components/widget";
114
+
115
+ export default async function Page() {
116
+ const data = await fetchData();
117
+ return <Widget spec={{ widget: "stat-group", data }} />;
118
+ }
119
+ ```
120
+
121
+ For pages where SSR hydration mismatch is a concern, use dynamic import:
122
+
123
+ ```tsx
124
+ import dynamic from "next/dynamic";
125
+ const Widget = dynamic(
126
+ () => import("@/components/widget").then((m) => m.Widget),
127
+ { ssr: false }
128
+ );
129
+ ```
130
+
91
131
  ## Documentation
92
132
 
93
133
  - [Widget Reference](docs/widgets.md) — Schema, mapping, options, theming
@@ -2,7 +2,6 @@ import { CSSResult } from 'lit';
2
2
  import { LitElement } from 'lit';
3
3
  import { nothing } from 'lit';
4
4
  import { TemplateResult } from 'lit-html';
5
- import { UWidgetElementProps } from './types/jsx.js';
6
5
 
7
6
  /**
8
7
  * Chart widget type identifiers using dot notation (`chart.<variant>`).
@@ -283,7 +282,18 @@ export declare interface UWidgetColumnDefinition {
283
282
  align?: 'left' | 'center' | 'right';
284
283
  }
285
284
 
286
- export { UWidgetElementProps }
285
+ export declare interface UWidgetElementProps {
286
+ /** Widget spec — object (via property binding) or JSON string (via attribute). */
287
+ spec?: UWidgetSpec | string;
288
+ /** Theme override. Omit for prefers-color-scheme auto-detection. */
289
+ theme?: 'light' | 'dark';
290
+ /** BCP 47 locale tag, e.g. 'ko-KR'. */
291
+ locale?: string;
292
+ id?: string;
293
+ class?: string;
294
+ style?: string;
295
+ [key: string]: unknown;
296
+ }
287
297
 
288
298
  /**
289
299
  * Event payload emitted by `<u-widget>` via the `u-widget-event` custom event.
@@ -518,3 +528,22 @@ export declare interface ValidationResult {
518
528
  export declare type WidgetType = ChartType | 'metric' | 'stat-group' | 'gauge' | 'progress' | 'table' | 'list' | 'form' | 'confirm' | 'compose' | 'markdown' | 'image' | 'callout' | 'kv' | 'code' | 'citation' | 'status' | 'steps' | 'rating' | 'video' | 'gallery' | 'actions' | 'divider' | 'header';
519
529
 
520
530
  export { }
531
+
532
+ declare global {
533
+ interface HTMLElementTagNameMap {
534
+ 'u-widget': import('@iyulab/u-widgets').UWidget;
535
+ }
536
+ namespace JSX {
537
+ interface IntrinsicElements {
538
+ 'u-widget': UWidgetElementProps;
539
+ }
540
+ }
541
+ }
542
+
543
+ declare module "react" {
544
+ namespace JSX {
545
+ interface IntrinsicElements {
546
+ "u-widget": UWidgetElementProps;
547
+ }
548
+ }
549
+ }
package/dist/u-widgets.js CHANGED
@@ -1,10 +1,10 @@
1
- import { g as ve } from "./formdown-BWJ6QGJs.js";
1
+ import { g as be } from "./formdown-BWJ6QGJs.js";
2
2
  import { p as Nt, r as Ft } from "./formdown-BWJ6QGJs.js";
3
- import { i as be } from "./infer-CNOiD2dS.js";
4
- import { t as b, n as we } from "./tokens-x1kDxgG8.js";
3
+ import { i as we } from "./infer-CNOiD2dS.js";
4
+ import { t as b, n as ye } from "./tokens-x1kDxgG8.js";
5
5
  import { css as w, LitElement as y, nothing as l, html as o } from "lit";
6
6
  import { property as h, customElement as x, state as S } from "lit/decorators.js";
7
- const ye = /* @__PURE__ */ new Set([
7
+ const xe = /* @__PURE__ */ new Set([
8
8
  "text",
9
9
  "email",
10
10
  "password",
@@ -21,7 +21,7 @@ const ye = /* @__PURE__ */ new Set([
21
21
  "range",
22
22
  "radio",
23
23
  "checkbox"
24
- ]), ie = 10, xe = /* @__PURE__ */ new Set([
24
+ ]), ie = 10, $e = /* @__PURE__ */ new Set([
25
25
  "stat-group",
26
26
  "table",
27
27
  "list",
@@ -38,7 +38,7 @@ const ye = /* @__PURE__ */ new Set([
38
38
  "chart.funnel",
39
39
  "chart.waterfall",
40
40
  "chart.treemap"
41
- ]), $e = /* @__PURE__ */ new Set(["metric", "gauge", "progress", "header", "code", "rating", "video"]);
41
+ ]), _e = /* @__PURE__ */ new Set(["metric", "gauge", "progress", "header", "code", "rating", "video"]);
42
42
  function Y(e, t = 0) {
43
43
  const a = [], r = [];
44
44
  if (t > ie)
@@ -49,7 +49,7 @@ function Y(e, t = 0) {
49
49
  if (typeof i.widget != "string" || i.widget.length === 0)
50
50
  return a.push('Required field "widget" must be a non-empty string'), { valid: !1, errors: a, warnings: r };
51
51
  const s = i.widget;
52
- if (i.type !== void 0 && i.type !== "u-widget" && a.push('"type" must be "u-widget" if specified'), i.fields !== void 0 && i.formdown !== void 0 && a.push('"fields" and "formdown" are mutually exclusive'), i.data !== void 0 && (xe.has(s) && !Array.isArray(i.data) && a.push(`"${s}" expects "data" to be an array, got ${typeof i.data}`), $e.has(s) && (Array.isArray(i.data) || typeof i.data != "object") && a.push(`"${s}" expects "data" to be an object, got ${Array.isArray(i.data) ? "array" : typeof i.data}`)), s === "compose") {
52
+ if (i.type !== void 0 && i.type !== "u-widget" && a.push('"type" must be "u-widget" if specified'), i.fields !== void 0 && i.formdown !== void 0 && a.push('"fields" and "formdown" are mutually exclusive'), i.data !== void 0 && ($e.has(s) && !Array.isArray(i.data) && a.push(`"${s}" expects "data" to be an array, got ${typeof i.data}`), _e.has(s) && (Array.isArray(i.data) || typeof i.data != "object") && a.push(`"${s}" expects "data" to be an object, got ${Array.isArray(i.data) ? "array" : typeof i.data}`)), s === "compose") {
53
53
  if (!Array.isArray(i.children))
54
54
  a.push('"compose" widget requires a "children" array');
55
55
  else
@@ -70,11 +70,11 @@ function Y(e, t = 0) {
70
70
  if (Array.isArray(i.fields))
71
71
  for (let n = 0; n < i.fields.length; n++) {
72
72
  const d = i.fields[n];
73
- d == null || typeof d != "object" || typeof d.field != "string" ? a.push(`fields[${n}] must have a "field" string property`) : d.type != null && !ye.has(d.type) && r.push(`fields[${n}].type "${d.type}" is not a recognized field type`);
73
+ d == null || typeof d != "object" || typeof d.field != "string" ? a.push(`fields[${n}] must have a "field" string property`) : d.type != null && !xe.has(d.type) && r.push(`fields[${n}].type "${d.type}" is not a recognized field type`);
74
74
  }
75
75
  if (typeof i.formdown == "string" && i.formdown.length > 0 && !i.fields)
76
76
  try {
77
- ve()(i.formdown);
77
+ be()(i.formdown);
78
78
  } catch {
79
79
  r.push("formdown string could not be parsed — check syntax");
80
80
  }
@@ -84,7 +84,7 @@ function Y(e, t = 0) {
84
84
  (d == null || typeof d != "object" || typeof d.label != "string" || typeof d.action != "string") && a.push(`actions[${n}] must have "label" and "action" string properties`);
85
85
  }
86
86
  if (i.mapping && typeof i.mapping == "object" && i.data) {
87
- const n = i.mapping, d = _e(i.data);
87
+ const n = i.mapping, d = ke(i.data);
88
88
  if (d)
89
89
  for (const c of ["x", "y", "label", "value", "color", "size", "axis", "primary", "secondary", "icon", "avatar", "trailing"]) {
90
90
  const p = n[c];
@@ -95,7 +95,7 @@ function Y(e, t = 0) {
95
95
  }
96
96
  return { valid: a.length === 0, errors: a, warnings: r };
97
97
  }
98
- function _e(e) {
98
+ function ke(e) {
99
99
  if (Array.isArray(e) && e.length > 0 && e[0] && typeof e[0] == "object")
100
100
  return new Set(Object.keys(e[0]));
101
101
  if (e && typeof e == "object" && !Array.isArray(e))
@@ -104,7 +104,7 @@ function _e(e) {
104
104
  function Dt(e) {
105
105
  return Y(e).valid;
106
106
  }
107
- const se = ["B", "KB", "MB", "GB", "TB"], ke = /* @__PURE__ */ new Set([
107
+ const se = ["B", "KB", "MB", "GB", "TB"], ze = /* @__PURE__ */ new Set([
108
108
  "KRW",
109
109
  "JPY",
110
110
  "VND",
@@ -124,7 +124,7 @@ const se = ["B", "KB", "MB", "GB", "TB"], ke = /* @__PURE__ */ new Set([
124
124
  "XOF",
125
125
  "XPF"
126
126
  ]);
127
- function ze(e, t, a) {
127
+ function pe(e, t, a) {
128
128
  if (e == null) return "";
129
129
  const [r, i] = t?.split(":") ?? [];
130
130
  switch (r) {
@@ -153,7 +153,7 @@ function Ae(e, t, a) {
153
153
  if (isNaN(r)) return String(e);
154
154
  const i = t || "USD";
155
155
  try {
156
- const s = ke.has(i.toUpperCase());
156
+ const s = ze.has(i.toUpperCase());
157
157
  return new Intl.NumberFormat(a, {
158
158
  style: "currency",
159
159
  currency: i,
@@ -322,7 +322,7 @@ const R = {
322
322
  function jt(e, t) {
323
323
  L.set(e.toLowerCase(), { ...R, ...t });
324
324
  }
325
- function pe(e) {
325
+ function ue(e) {
326
326
  if (!e) return R;
327
327
  const t = e.toLowerCase();
328
328
  if (L.has(t)) return L.get(t);
@@ -351,14 +351,15 @@ function Ie(e) {
351
351
  if (typeof document < "u" && document.documentElement?.lang)
352
352
  return document.documentElement.lang;
353
353
  }
354
- var Ne = Object.defineProperty, Fe = Object.getOwnPropertyDescriptor, ue = (e, t, a, r) => {
354
+ var Ne = Object.defineProperty, Fe = Object.getOwnPropertyDescriptor, ge = (e, t, a, r) => {
355
355
  for (var i = r > 1 ? void 0 : r ? Fe(t, a) : t, s = e.length - 1, n; s >= 0; s--)
356
356
  (n = e[s]) && (i = (r ? n(t, a, i) : n(i)) || i);
357
357
  return r && i && Ne(t, a, i), i;
358
358
  };
359
- function ne(e) {
359
+ function ne(e, t) {
360
+ const a = e.value, r = e.format;
360
361
  return {
361
- value: e.value ?? 0,
362
+ value: r ? pe(a, r, t) : a ?? 0,
362
363
  label: e.label,
363
364
  unit: e.unit,
364
365
  prefix: e.prefix,
@@ -366,7 +367,9 @@ function ne(e) {
366
367
  change: e.change,
367
368
  trend: e.trend,
368
369
  icon: e.icon,
369
- description: e.description
370
+ description: e.description,
371
+ format: e.format,
372
+ variant: e.variant
370
373
  };
371
374
  }
372
375
  let B = class extends y {
@@ -374,20 +377,22 @@ let B = class extends y {
374
377
  super(...arguments), this.spec = null;
375
378
  }
376
379
  render() {
377
- return this.spec?.data ? this.spec.widget === "stat-group" ? this.renderStatGroup() : this.renderMetric(ne(this.spec.data)) : l;
380
+ if (!this.spec?.data) return l;
381
+ const e = this.spec.options?.locale;
382
+ return this.spec.widget === "stat-group" ? this.renderStatGroup(e) : this.renderMetric(ne(this.spec.data, e));
378
383
  }
379
- renderStatGroup() {
380
- const e = this.spec.data;
381
- return Array.isArray(e) ? o`
384
+ renderStatGroup(e) {
385
+ const t = this.spec.data;
386
+ return Array.isArray(t) ? o`
382
387
  <div class="stat-group" part="stat-group">
383
- ${e.map((t) => this.renderMetric(ne(t)))}
388
+ ${t.map((a) => this.renderMetric(ne(a, e)))}
384
389
  </div>
385
390
  ` : l;
386
391
  }
387
392
  renderMetric(e) {
388
393
  const t = e.trend === "up" ? "↑" : e.trend === "down" ? "↓" : e.trend === "flat" ? "→" : "", a = e.label ? `${e.label}: ${e.prefix ?? ""}${e.value}${e.unit ?? ""}${e.suffix ?? ""}` : void 0;
389
394
  return o`
390
- <div class="metric" part="metric" aria-label=${a ?? l}>
395
+ <div class="metric" part="metric" aria-label=${a ?? l} data-variant=${e.variant ?? l}>
391
396
  ${e.icon ? o`<div class="metric-icon" part="icon">${e.icon}</div>` : l}
392
397
  ${e.label ? o`<div class="metric-label" part="label">${e.label}</div>` : l}
393
398
  <div class="metric-value" part="value">
@@ -464,6 +469,12 @@ B.styles = [b, w`
464
469
  .metric-icon { font-size: 1.25rem; line-height: 1; margin-bottom: 2px; }
465
470
  .metric-description { font-size: 0.75rem; color: var(--u-widget-text-secondary, #64748b); margin-top: 2px; line-height: 1.3; }
466
471
 
472
+ /* ── variant colors ── */
473
+ .metric[data-variant="success"] .metric-value { color: var(--u-widget-positive, #16a34a); }
474
+ .metric[data-variant="danger"] .metric-value { color: var(--u-widget-negative, #dc2626); }
475
+ .metric[data-variant="warning"] .metric-value { color: var(--u-widget-warning, #d97706); }
476
+ .metric[data-variant="info"] .metric-value { color: var(--u-widget-info, #2563eb); }
477
+
467
478
  /* ── stat-group ── */
468
479
  .stat-group {
469
480
  display: flex;
@@ -501,13 +512,13 @@ B.styles = [b, w`
501
512
  }
502
513
  }
503
514
  `];
504
- ue([
515
+ ge([
505
516
  h({ type: Object })
506
517
  ], B.prototype, "spec", 2);
507
- B = ue([
518
+ B = ge([
508
519
  x("u-metric")
509
520
  ], B);
510
- var Me = Object.defineProperty, Te = Object.getOwnPropertyDescriptor, ge = (e, t, a, r) => {
521
+ var Me = Object.defineProperty, Te = Object.getOwnPropertyDescriptor, fe = (e, t, a, r) => {
511
522
  for (var i = r > 1 ? void 0 : r ? Te(t, a) : t, s = e.length - 1, n; s >= 0; s--)
512
523
  (n = e[s]) && (i = (r ? n(t, a, i) : n(i)) || i);
513
524
  return r && i && Me(t, a, i), i;
@@ -703,10 +714,10 @@ W.styles = [b, w`
703
714
  }
704
715
  }
705
716
  `];
706
- ge([
717
+ fe([
707
718
  h({ type: Object })
708
719
  ], W.prototype, "spec", 2);
709
- W = ge([
720
+ W = fe([
710
721
  x("u-gauge")
711
722
  ], W);
712
723
  var qe = Object.defineProperty, Be = Object.getOwnPropertyDescriptor, C = (e, t, a, r) => {
@@ -780,7 +791,7 @@ let z = class extends y {
780
791
  }
781
792
  get _locale() {
782
793
  const e = this.spec?.options?.locale;
783
- return pe(typeof e == "string" ? e : void 0);
794
+ return ue(typeof e == "string" ? e : void 0);
784
795
  }
785
796
  renderTable() {
786
797
  const e = this.spec.data, t = this.getColumns(e), a = this._locale, r = this.spec.options?.sortable !== !1, i = !!this.spec.options?.searchable, s = !!this.spec.options?.compact, n = Number(this.spec.options?.pageSize) || 0, d = this._searchQuery ? this.filterData(e, t) : e, c = this._sortField && this._sortDir ? this.sortData(d) : d, p = n > 0 ? Math.max(1, Math.ceil(c.length / n)) : 1, g = Math.min(this._page, p - 1), f = n > 0 ? c.slice(g * n, (g + 1) * n) : c, u = i ? o`
@@ -835,7 +846,7 @@ let z = class extends y {
835
846
  >
836
847
  ${t.map(
837
848
  (_) => o`<td data-align=${_.align ?? "left"} part="td"
838
- >${ze(v[_.field], _.format, typeof this.spec.options?.locale == "string" ? this.spec.options.locale : void 0)}</td
849
+ >${pe(v[_.field], _.format, typeof this.spec.options?.locale == "string" ? this.spec.options.locale : void 0)}</td
839
850
  >`
840
851
  )}
841
852
  </tr>
@@ -1498,7 +1509,7 @@ let j = class extends y {
1498
1509
  }
1499
1510
  get _locale() {
1500
1511
  const e = this.spec?.options?.locale;
1501
- return pe(typeof e == "string" ? e : void 0);
1512
+ return ue(typeof e == "string" ? e : void 0);
1502
1513
  }
1503
1514
  _validate() {
1504
1515
  const e = this.spec?.fields ?? [], t = {}, a = this._locale;
@@ -1943,7 +1954,7 @@ Z([
1943
1954
  I = Z([
1944
1955
  x("u-compose")
1945
1956
  ], I);
1946
- var Ge = Object.defineProperty, Xe = Object.getOwnPropertyDescriptor, fe = (e, t, a, r) => {
1957
+ var Ge = Object.defineProperty, Xe = Object.getOwnPropertyDescriptor, he = (e, t, a, r) => {
1947
1958
  for (var i = r > 1 ? void 0 : r ? Xe(t, a) : t, s = e.length - 1, n; s >= 0; s--)
1948
1959
  (n = e[s]) && (i = (r ? n(t, a, i) : n(i)) || i);
1949
1960
  return r && i && Ge(t, a, i), i;
@@ -2193,13 +2204,13 @@ K.styles = [b, w`
2193
2204
  }
2194
2205
  }
2195
2206
  `];
2196
- fe([
2207
+ he([
2197
2208
  h({ type: Object })
2198
2209
  ], K.prototype, "spec", 2);
2199
- K = fe([
2210
+ K = he([
2200
2211
  x("u-content")
2201
2212
  ], K);
2202
- var Je = Object.defineProperty, Ye = Object.getOwnPropertyDescriptor, he = (e, t, a, r) => {
2213
+ var Je = Object.defineProperty, Ye = Object.getOwnPropertyDescriptor, me = (e, t, a, r) => {
2203
2214
  for (var i = r > 1 ? void 0 : r ? Ye(t, a) : t, s = e.length - 1, n; s >= 0; s--)
2204
2215
  (n = e[s]) && (i = (r ? n(t, a, i) : n(i)) || i);
2205
2216
  return r && i && Je(t, a, i), i;
@@ -2329,10 +2340,10 @@ H.styles = [b, w`
2329
2340
  }
2330
2341
  }
2331
2342
  `];
2332
- he([
2343
+ me([
2333
2344
  h({ type: Object })
2334
2345
  ], H.prototype, "spec", 2);
2335
- H = he([
2346
+ H = me([
2336
2347
  x("u-kv")
2337
2348
  ], H);
2338
2349
  var Ze = Object.defineProperty, Qe = Object.getOwnPropertyDescriptor, G = (e, t, a, r) => {
@@ -2400,7 +2411,7 @@ function D(e, t) {
2400
2411
  `).map((r) => `<span class="hl-${t}">${r}</span>`).join(`
2401
2412
  `) : `<span class="hl-${t}">${a}</span>`;
2402
2413
  }
2403
- function me(e, t, a) {
2414
+ function ve(e, t, a) {
2404
2415
  let r = t + 1;
2405
2416
  for (; r < e.length; ) {
2406
2417
  if (e[r] === "\\") {
@@ -2435,7 +2446,7 @@ function it(e, t) {
2435
2446
  }
2436
2447
  const f = e[p];
2437
2448
  if (f === '"' || f === "'" || f === "`" && d) {
2438
- const u = me(e, p, f);
2449
+ const u = ve(e, p, f);
2439
2450
  c += D(e.slice(p, u), "s"), p = u;
2440
2451
  continue;
2441
2452
  }
@@ -2476,7 +2487,7 @@ function st(e) {
2476
2487
  for (; a < r; ) {
2477
2488
  const i = e[a];
2478
2489
  if (i === '"') {
2479
- const n = me(e, a, '"'), d = e.slice(a, n), c = e.slice(n).trimStart();
2490
+ const n = ve(e, a, '"'), d = e.slice(a, n), c = e.slice(n).trimStart();
2480
2491
  t += D(d, c[0] === ":" ? "k" : "s"), a = n;
2481
2492
  continue;
2482
2493
  }
@@ -3731,11 +3742,11 @@ let E = class extends y {
3731
3742
  const e = Y(this.spec);
3732
3743
  if (!e.valid)
3733
3744
  return this.renderError(e.errors);
3734
- const t = we(this.spec);
3745
+ const t = ye(this.spec);
3735
3746
  return this.renderWidget(t);
3736
3747
  }
3737
3748
  renderWidget(e) {
3738
- const t = e.widget, a = e.mapping ?? be(t, e.data);
3749
+ const t = e.widget, a = e.mapping ?? we(t, e.data);
3739
3750
  let r = a ? { ...e, mapping: a } : e;
3740
3751
  const i = Ie(this.locale);
3741
3752
  i && !r.options?.locale && (r = {
@@ -4100,14 +4111,14 @@ E = J([
4100
4111
  export {
4101
4112
  E as UWidget,
4102
4113
  A as formatTemplate,
4103
- ze as formatValue,
4114
+ pe as formatValue,
4104
4115
  Ot as getDefaultLocale,
4105
4116
  Et as getEffectiveLocale,
4106
- ve as getFormdownParser,
4107
- pe as getLocaleStrings,
4108
- be as infer,
4117
+ be as getFormdownParser,
4118
+ ue as getLocaleStrings,
4119
+ we as infer,
4109
4120
  Dt as isWidgetSpec,
4110
- we as normalize,
4121
+ ye as normalize,
4111
4122
  Nt as parseFormdown,
4112
4123
  Ft as registerFormdownParser,
4113
4124
  jt as registerLocale,