@cascivo/react 0.7.1 → 0.9.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
@@ -10,7 +10,7 @@
10
10
  [![license](https://img.shields.io/npm/l/%40cascivo%2Freact?style=flat-square&color=0079bf)](https://github.com/cascivo/cascivo/blob/main/LICENSE)
11
11
  ![types](https://img.shields.io/badge/types-included-0079bf?style=flat-square&logo=typescript&logoColor=white)
12
12
 
13
- [npm](https://www.npmjs.com/package/@cascivo/react) · [cascivo.com](https://cascivo.com) · [Docs](https://docs.cascivo.com) · [Storybook](https://storybook.cascivo.com) · [GitHub](https://github.com/cascivo/cascivo)
13
+ [npm](https://www.npmjs.com/package/@cascivo/react) · [cascivo.com](https://cascivo.com) · [Docs](https://cascivo.com/docs) · [Storybook](https://storybook.cascivo.com) · [GitHub](https://github.com/cascivo/cascivo)
14
14
 
15
15
  </div>
16
16
 
@@ -36,6 +36,11 @@ supplies the tokens and themes the components read.
36
36
  Charts live in a separate package — add [`@cascivo/charts`](https://github.com/cascivo/cascivo/tree/main/packages/charts)
37
37
  for `LineChart`, `AreaChart`, `BarChart`, `Sparkline`, and more.
38
38
 
39
+ > **Types are the reference.** The shipped `dist/index.d.ts` is a self-contained, flat
40
+ > rollup — every component's `…Props` interface is real, documentation-grade API. Reading
41
+ > it (or the per-component [`/llms/<name>.md`](https://cascivo.com/llms.txt)) is the fastest
42
+ > way to learn a component's props with no web access.
43
+
39
44
  ### Framework setup (Next.js App Router)
40
45
 
41
46
  In a Server Component file (e.g. `app/layout.tsx`), import the themes once:
@@ -58,12 +63,20 @@ RSC without any extra wrapper.
58
63
  > only if you prefer one explicit stylesheet over per-component tree-shaking, or
59
64
  > for Vite SSR (below), where it is required.
60
65
 
61
- > **Vite SSR / TanStack Start / Remix / workerd?** Those per-component `.css`
62
- > imports need a bundler to resolve them; a bare server-side ESM loader throws
63
- > `Unknown file extension ".css"`. Add `ssr: { noExternal: [/^@cascivo\//] }` (or
64
- > the `cascivoSsr()` plugin from `@cascivo/vite-plugin`) and import
65
- > `@cascivo/react/styles.css` once in your root entry. Full recipe:
66
- > [USING-WITH-VITE-SSR.md](https://github.com/cascivo/cascivo/blob/main/docs/USING-WITH-VITE-SSR.md).
66
+ > **Vite SSR / TanStack Start / Remix / workerd?** The 4-line SSR checklist (full
67
+ > recipe: [USING-WITH-VITE-SSR.md](https://github.com/cascivo/cascivo/blob/main/docs/USING-WITH-VITE-SSR.md)):
68
+ >
69
+ > 1. **`ssr: { noExternal: [/^@cascivo\//] }`** in `vite.config` (or the
70
+ > `cascivoSsr()` plugin from `@cascivo/vite-plugin`). Without it a bare
71
+ > server-side ESM loader can't resolve the per-component `.css` side-effect
72
+ > imports and throws `Unknown file extension ".css"`.
73
+ > 2. **`@preact/signals-react` 3.x** — on React 19 the 2.x line fails to load. The
74
+ > peer range enforces `>=3`.
75
+ > 3. **Import the CSS once** in your root entry: `@cascivo/react/styles.css` +
76
+ > `@cascivo/themes/all` (+ `@cascivo/charts/styles.css` if you use charts).
77
+ > 4. **Theme without a mismatch:** inline `themePreloadScript()` in `<head>` and add
78
+ > `suppressHydrationWarning` to `<html>`, or hard-code `data-theme` for a fixed theme.
79
+ >
67
80
  > Next.js App Router needs none of this.
68
81
 
69
82
  ## Use
@@ -203,7 +216,7 @@ routing break after adding one of these, check that the import resolves to
203
216
 
204
217
  ## Component index
205
218
 
206
- 192 components, exported from `@cascivo/react`. Full props, examples, and live demos at [docs.cascivo.com](https://docs.cascivo.com).
219
+ 192 components, exported from `@cascivo/react`. Full props, examples, and live demos at [cascivo.com/docs](https://cascivo.com/docs).
207
220
 
208
221
  ### Inputs
209
222
 
@@ -428,6 +441,6 @@ pnpm add @cascivo/react
428
441
 
429
442
  ---
430
443
 
431
- [cascivo.com](https://cascivo.com) · [Docs](https://docs.cascivo.com) · [Storybook](https://storybook.cascivo.com) · [GitHub](https://github.com/cascivo/cascivo) · AI agents: read [`llms.txt`](https://cascivo.com/llms.txt) (install steps + component index, plain text) or use [`@cascivo/mcp`](https://github.com/cascivo/cascivo/tree/main/packages/mcp) and [`registry.json`](https://github.com/cascivo/cascivo/blob/main/registry.json) · MIT
444
+ [cascivo.com](https://cascivo.com) · [Docs](https://cascivo.com/docs) · [Storybook](https://storybook.cascivo.com) · [GitHub](https://github.com/cascivo/cascivo) · AI agents: read [`llms.txt`](https://cascivo.com/llms.txt) (install steps + component index, plain text) or use [`@cascivo/mcp`](https://github.com/cascivo/cascivo/tree/main/packages/mcp) and [`registry.json`](https://github.com/cascivo/cascivo/blob/main/registry.json) · MIT
432
445
 
433
446
  <div align="center"><a href="https://cascivo.com"><img src="https://cascivo.com/favicon.svg" width="28" height="28" alt="cascivo"></a></div>
@@ -15,31 +15,43 @@ var s = n({
15
15
  error: {}
16
16
  }
17
17
  });
18
- function c({ src: n, alt: c = "", fallback: l, size: u = "md", status: d, className: f, ...p }) {
18
+ function c({ src: n, alt: c = "", name: u, fallback: d, size: f = "md", status: p, className: m, ...h }) {
19
19
  i();
20
- let [m, h] = r(s), g = !!n && m.value !== "error", _ = c || l;
20
+ let [g, _] = r(s), v = !!n && g.value !== "error", y = d ?? l(u), b = c || u || d;
21
21
  return /* @__PURE__ */ o("span", {
22
- "data-size": u,
23
- "data-status": d,
24
- className: t(e.avatar, f),
25
- role: g || !_ ? void 0 : "img",
26
- "aria-label": g ? void 0 : _ || void 0,
27
- ...p,
28
- children: [g ? /* @__PURE__ */ a("img", {
22
+ "data-size": f,
23
+ "data-status": p,
24
+ className: t(e.avatar, m),
25
+ role: v || !b ? void 0 : "img",
26
+ "aria-label": v ? void 0 : b || void 0,
27
+ ...h,
28
+ children: [v ? /* @__PURE__ */ a("img", {
29
29
  className: e.image,
30
30
  src: n,
31
- alt: c,
32
- onLoad: () => h("LOADED"),
33
- onError: () => h("ERROR")
31
+ alt: c || u || "",
32
+ onLoad: () => _("LOADED"),
33
+ onError: () => _("ERROR")
34
34
  }) : /* @__PURE__ */ a("span", {
35
35
  className: e.fallback,
36
36
  "aria-hidden": "true",
37
- children: l
38
- }), d && /* @__PURE__ */ a("span", {
37
+ children: y
38
+ }), p && /* @__PURE__ */ a("span", {
39
39
  className: e.status,
40
40
  "aria-hidden": "true"
41
41
  })]
42
42
  });
43
43
  }
44
+ function l(e) {
45
+ if (!e) return;
46
+ let t = e.trim().split(/\s+/).filter(Boolean);
47
+ if (t.length !== 0) return (u(t[0]) + (t.length > 1 ? u(t[t.length - 1]) : "")).toLocaleUpperCase() || void 0;
48
+ }
49
+ function u(e) {
50
+ if (typeof Intl < "u" && "Segmenter" in Intl) {
51
+ let t = new Intl.Segmenter(void 0, { granularity: "grapheme" });
52
+ for (let n of t.segment(e)) return n.segment;
53
+ }
54
+ return [...e][0] ?? "";
55
+ }
44
56
  //#endregion
45
57
  export { c as Avatar };
@@ -13,149 +13,149 @@ var p = n({
13
13
  open: { on: { CLOSE: "closed" } }
14
14
  }
15
15
  });
16
- function m({ options: n, value: m, defaultValue: h, onChange: g, clearable: _ = !1, searchable: v = !0, label: y, hint: b, error: x, size: S = "md", disabled: C = !1, labels: w, className: T, id: E }) {
16
+ function m({ options: n, value: m, defaultValue: h, onValueChange: g, onChange: _, clearable: v = !1, searchable: y = !0, label: b, hint: x, error: S, size: C = "md", disabled: w = !1, labels: T, className: E, id: D }) {
17
17
  o();
18
- let [D, O] = r(p), k = d(), A = E ?? `cascade-combobox-${k}`, j = `${k}-listbox`, M = f(null), N = w?.placeholder ?? c(s.combobox.placeholder), P = w?.empty ?? c(s.combobox.empty), F = w?.clear ?? c(s.combobox.clear), I = w?.search ?? c(s.combobox.search), L = i(m ?? h);
19
- m !== void 0 && (L.value = m);
20
- let R = i(""), z = i(0), B = D.value === "open", V = n.filter((e) => !v || !R.value ? !0 : e.label.toLowerCase().includes(R.value.toLowerCase())), H = n.find((e) => e.value === L.value);
18
+ let [O, k] = r(p), A = d(), j = D ?? `cascade-combobox-${A}`, M = `${A}-listbox`, N = f(null), P = T?.placeholder ?? c(s.combobox.placeholder), F = T?.empty ?? c(s.combobox.empty), I = T?.clear ?? c(s.combobox.clear), L = T?.search ?? c(s.combobox.search), R = i(m ?? h);
19
+ m !== void 0 && (R.value = m);
20
+ let z = i(""), B = i(0), V = O.value === "open", H = n.filter((e) => !y || !z.value ? !0 : e.label.toLowerCase().includes(z.value.toLowerCase())), U = n.find((e) => e.value === R.value);
21
21
  a(() => {
22
- if (!B) return;
22
+ if (!V) return;
23
23
  let e = (e) => {
24
- let t = document.getElementById(`${k}-root`);
25
- t && !t.contains(e.target) && O("CLOSE");
24
+ let t = document.getElementById(`${A}-root`);
25
+ t && !t.contains(e.target) && k("CLOSE");
26
26
  };
27
27
  return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
28
28
  });
29
- let U = () => {
30
- C || (R.value = "", z.value = 0, O("OPEN"), setTimeout(() => M.current?.focus(), 0));
31
- }, W = () => {
32
- O("CLOSE"), R.value = "";
33
- }, G = (e) => {
34
- m === void 0 && (L.value = e), g?.(e), W();
35
- }, K = () => {
36
- m === void 0 && (L.value = void 0), g?.(void 0);
37
- }, q = V.flatMap((e, t) => e.disabled ? [] : [t]), J = (e) => {
38
- if (q.length === 0) return;
39
- let t = q[(q.indexOf(z.value) + e + q.length) % q.length];
40
- t !== void 0 && (z.value = t);
41
- }, Y = (e) => {
42
- (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") && (e.preventDefault(), U());
43
- }, X = (e) => {
29
+ let W = () => {
30
+ w || (z.value = "", B.value = 0, k("OPEN"), setTimeout(() => N.current?.focus(), 0));
31
+ }, G = () => {
32
+ k("CLOSE"), z.value = "";
33
+ }, K = g ?? _, q = (e) => {
34
+ m === void 0 && (R.value = e), K?.(e), G();
35
+ }, J = () => {
36
+ m === void 0 && (R.value = void 0), K?.(void 0);
37
+ }, Y = H.flatMap((e, t) => e.disabled ? [] : [t]), X = (e) => {
38
+ if (Y.length === 0) return;
39
+ let t = Y[(Y.indexOf(B.value) + e + Y.length) % Y.length];
40
+ t !== void 0 && (B.value = t);
41
+ }, Z = (e) => {
42
+ (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") && (e.preventDefault(), W());
43
+ }, Q = (e) => {
44
44
  switch (e.key) {
45
45
  case "ArrowDown":
46
- e.preventDefault(), J(1);
46
+ e.preventDefault(), X(1);
47
47
  break;
48
48
  case "ArrowUp":
49
- e.preventDefault(), J(-1);
49
+ e.preventDefault(), X(-1);
50
50
  break;
51
51
  case "Enter": {
52
52
  e.preventDefault();
53
- let t = V[z.value];
54
- t && !t.disabled && G(t.value);
53
+ let t = H[B.value];
54
+ t && !t.disabled && q(t.value);
55
55
  break;
56
56
  }
57
57
  case "Escape":
58
- e.preventDefault(), W();
58
+ e.preventDefault(), G();
59
59
  break;
60
60
  case "Tab":
61
- W();
61
+ G();
62
62
  break;
63
63
  }
64
- }, Z = (e) => `${k}-option-${e}`;
64
+ }, $ = (e) => `${A}-option-${e}`;
65
65
  return /* @__PURE__ */ u("div", {
66
- id: `${k}-root`,
67
- className: t(e.wrapper, T),
68
- "data-state": x ? "error" : D.value,
69
- "data-size": S,
66
+ id: `${A}-root`,
67
+ className: t(e.wrapper, E),
68
+ "data-state": S ? "error" : O.value,
69
+ "data-size": C,
70
70
  children: [
71
- y && /* @__PURE__ */ l("label", {
71
+ b && /* @__PURE__ */ l("label", {
72
72
  className: e.label,
73
- htmlFor: A,
74
- children: y
73
+ htmlFor: j,
74
+ children: b
75
75
  }),
76
76
  /* @__PURE__ */ u("div", {
77
77
  className: e.field,
78
78
  children: [/* @__PURE__ */ u("button", {
79
- id: A,
79
+ id: j,
80
80
  type: "button",
81
81
  role: "combobox",
82
- "aria-expanded": B,
83
- "aria-controls": j,
82
+ "aria-expanded": V,
83
+ "aria-controls": M,
84
84
  "aria-haspopup": "listbox",
85
- "aria-activedescendant": B && z.value >= 0 ? Z(z.value) : void 0,
86
- "aria-invalid": x ? !0 : void 0,
87
- "aria-describedby": x ? `${k}-error` : b ? `${k}-hint` : void 0,
85
+ "aria-activedescendant": V && B.value >= 0 ? $(B.value) : void 0,
86
+ "aria-invalid": S ? !0 : void 0,
87
+ "aria-describedby": S ? `${A}-error` : x ? `${A}-hint` : void 0,
88
88
  className: e.trigger,
89
- disabled: C,
90
- onKeyDown: Y,
91
- onClick: B ? W : U,
89
+ disabled: w,
90
+ onKeyDown: Z,
91
+ onClick: V ? G : W,
92
92
  children: [/* @__PURE__ */ l("span", {
93
- className: t(e.value, H ? void 0 : e.placeholder),
94
- children: H?.label ?? N
93
+ className: t(e.value, U ? void 0 : e.placeholder),
94
+ children: U?.label ?? P
95
95
  }), /* @__PURE__ */ l("span", {
96
96
  className: e.chevron,
97
97
  "aria-hidden": "true"
98
98
  })]
99
- }), _ && L.value !== void 0 && /* @__PURE__ */ l("button", {
99
+ }), v && R.value !== void 0 && /* @__PURE__ */ l("button", {
100
100
  type: "button",
101
101
  className: e.clear,
102
- "aria-label": F,
102
+ "aria-label": I,
103
103
  onClick: (e) => {
104
- e.stopPropagation(), K();
104
+ e.stopPropagation(), J();
105
105
  },
106
106
  children: "✕"
107
107
  })]
108
108
  }),
109
109
  /* @__PURE__ */ u("div", {
110
110
  role: "listbox",
111
- id: j,
111
+ id: M,
112
112
  className: e.listbox,
113
- "data-state": B ? "open" : "closed",
114
- "aria-label": y,
115
- children: [v && B && /* @__PURE__ */ l("div", {
113
+ "data-state": V ? "open" : "closed",
114
+ "aria-label": b,
115
+ children: [y && V && /* @__PURE__ */ l("div", {
116
116
  className: e.searchWrapper,
117
117
  children: /* @__PURE__ */ l("input", {
118
- ref: M,
118
+ ref: N,
119
119
  type: "text",
120
120
  className: e.search,
121
- value: R.value,
121
+ value: z.value,
122
122
  onChange: (e) => {
123
- R.value = e.target.value, z.value = 0;
123
+ z.value = e.target.value, B.value = 0;
124
124
  },
125
- onKeyDown: X,
126
- "aria-label": I,
125
+ onKeyDown: Q,
126
+ "aria-label": L,
127
127
  autoComplete: "off"
128
128
  })
129
- }), V.length === 0 ? /* @__PURE__ */ l("div", {
129
+ }), H.length === 0 ? /* @__PURE__ */ l("div", {
130
130
  className: e.empty,
131
- children: P
132
- }) : V.map((t, n) => /* @__PURE__ */ l("div", {
133
- id: Z(n),
131
+ children: F
132
+ }) : H.map((t, n) => /* @__PURE__ */ l("div", {
133
+ id: $(n),
134
134
  role: "option",
135
- "aria-selected": t.value === L.value,
135
+ "aria-selected": t.value === R.value,
136
136
  "aria-disabled": t.disabled || void 0,
137
- "data-state": n === z.value ? "active" : void 0,
137
+ "data-state": n === B.value ? "active" : void 0,
138
138
  "data-disabled": t.disabled || void 0,
139
139
  className: e.option,
140
140
  onMouseEnter: () => {
141
- t.disabled || (z.value = n);
141
+ t.disabled || (B.value = n);
142
142
  },
143
143
  onClick: () => {
144
- t.disabled || G(t.value);
144
+ t.disabled || q(t.value);
145
145
  },
146
146
  children: t.label
147
147
  }, t.value))]
148
148
  }),
149
- x && /* @__PURE__ */ l("span", {
150
- id: `${k}-error`,
149
+ S && /* @__PURE__ */ l("span", {
150
+ id: `${A}-error`,
151
151
  className: e.error,
152
152
  role: "alert",
153
- children: x
153
+ children: S
154
154
  }),
155
- !x && b && /* @__PURE__ */ l("span", {
156
- id: `${k}-hint`,
155
+ !S && x && /* @__PURE__ */ l("span", {
156
+ id: `${A}-hint`,
157
157
  className: e.hint,
158
- children: b
158
+ children: x
159
159
  })
160
160
  ]
161
161
  });