@kahitsan/ksui 0.34.1 → 0.35.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kahitsan/ksui",
3
- "version": "0.34.1",
3
+ "version": "0.35.0",
4
4
  "description": "ksui is a standalone set of SolidJS UI components for KahitSan/Hilinga and any SolidJS app. Published to the public npm registry and consumed as a normal dependency. Ships source under a `solid` export condition so the consumer's vite-plugin-solid compiles it with only solid-js externalized; it depends on nothing but solid-js + lucide-solid and injects its own CSS.",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -64,6 +64,7 @@ export function buildInitialsSvg(name: string): string {
64
64
  `<circle cx="50" cy="50" r="50" fill="${color}"/>`,
65
65
  `<text x="50" y="50" text-anchor="middle" dominant-baseline="central" ` +
66
66
  `fill="white" font-size="${fontSize}" font-weight="bold" ` +
67
+ // rendered via <img src="data:...">, an isolated document — var(--ks-font-*) cannot resolve here, so left literal
67
68
  `font-family="system-ui,-apple-system,sans-serif">${initials}</text>`,
68
69
  "</svg>",
69
70
  ].join("");
@@ -118,7 +118,7 @@ const DATATABLE_CSS = `
118
118
  @media (min-width:640px){.ksui-datatable-search-input{width:18rem;}}
119
119
  .ksui-datatable-scroll{overflow-x:auto;transition:opacity 0.15s ease;}
120
120
  .ksui-datatable-table{width:100%;text-align:left;font-size:0.78125rem;line-height:1.3;border-collapse:collapse;}
121
- .ksui-datatable-thead{border-bottom:1px solid var(--ksui-dt-border,var(--ks-border,rgba(39,39,42,0.5)));background:var(--ksui-dt-thead-bg,color-mix(in srgb, var(--ks-fg, #ffffff) 3%, transparent));font-family:ui-monospace,"SF Mono","Cascadia Code",Menlo,Consolas,monospace;font-size:0.65625rem;text-transform:uppercase;letter-spacing:0.06em;color:var(--ksui-dt-muted,var(--ks-fg-subtle,#71717a));}
121
+ .ksui-datatable-thead{border-bottom:1px solid var(--ksui-dt-border,var(--ks-border,rgba(39,39,42,0.5)));background:var(--ksui-dt-thead-bg,color-mix(in srgb, var(--ks-fg, #ffffff) 3%, transparent));font-family:var(--ks-font-mono,ui-monospace,"SF Mono","Cascadia Code",Menlo,Consolas,monospace);font-size:0.65625rem;text-transform:uppercase;letter-spacing:0.06em;color:var(--ksui-dt-muted,var(--ks-fg-subtle,#71717a));}
122
122
  .ksui-datatable-th{padding:0.5625rem 0.875rem;background:var(--ksui-dt-thead-bg,color-mix(in srgb, var(--ks-fg, #ffffff) 3%, transparent));white-space:nowrap;}
123
123
  .ksui-datatable-th-num{text-align:right;}
124
124
  .ksui-datatable-th-sortable{cursor:pointer;transition:color 0.15s ease;}
@@ -130,9 +130,9 @@ const DATATABLE_CSS = `
130
130
  .ksui-datatable-row-clickable{cursor:pointer;}
131
131
  .ksui-datatable-row-clickable:active{background-color:var(--ksui-dt-row-active,color-mix(in srgb, var(--ks-border-strong, #3f3f46) 70%, transparent));}
132
132
  .ksui-datatable-td{padding:0.5rem 0.875rem;vertical-align:middle;white-space:nowrap;}
133
- .ksui-datatable-td-num{font-family:ui-monospace,"SF Mono","Cascadia Code",Menlo,Consolas,monospace;font-variant-numeric:tabular-nums;text-align:right;white-space:nowrap;color:var(--ksui-dt-text-strong,var(--ks-fg,#ffffff));}
134
- .ksui-datatable-code{display:block;font-family:ui-monospace,"SF Mono","Cascadia Code",Menlo,Consolas,monospace;font-size:0.71875rem;color:var(--ksui-dt-fg,var(--ks-fg,#ffffff));white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:34ch;}
135
- .ksui-datatable-badge{display:inline-block;font-family:ui-monospace,"SF Mono","Cascadia Code",Menlo,Consolas,monospace;font-size:0.625rem;padding:0.125rem 0.4375rem;border-radius:0.3125rem;letter-spacing:0.02em;background:var(--ksui-dt-control-bg,var(--ks-input-bg,#18181b));color:var(--ksui-dt-text,var(--ks-fg-muted,#a1a1aa));}
133
+ .ksui-datatable-td-num{font-family:var(--ks-font-mono,ui-monospace,"SF Mono","Cascadia Code",Menlo,Consolas,monospace);font-variant-numeric:tabular-nums;text-align:right;white-space:nowrap;color:var(--ksui-dt-text-strong,var(--ks-fg,#ffffff));}
134
+ .ksui-datatable-code{display:block;font-family:var(--ks-font-mono,ui-monospace,"SF Mono","Cascadia Code",Menlo,Consolas,monospace);font-size:0.71875rem;color:var(--ksui-dt-fg,var(--ks-fg,#ffffff));white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:34ch;}
135
+ .ksui-datatable-badge{display:inline-block;font-family:var(--ks-font-mono,ui-monospace,"SF Mono","Cascadia Code",Menlo,Consolas,monospace);font-size:0.625rem;padding:0.125rem 0.4375rem;border-radius:0.3125rem;letter-spacing:0.02em;background:var(--ksui-dt-control-bg,var(--ks-input-bg,#18181b));color:var(--ksui-dt-text,var(--ks-fg-muted,#a1a1aa));}
136
136
  .ksui-datatable-badge-ok{background:var(--ksui-dt-good-bg,color-mix(in srgb, var(--ks-success-fg, #34d399) 14%, transparent));color:var(--ksui-dt-good,var(--ks-success-fg,#34d399));}
137
137
  .ksui-datatable-badge-warn{background:var(--ksui-dt-accent-bg,color-mix(in srgb, var(--ks-accent, #fbbf24) 20%, transparent));color:var(--ksui-dt-accent,var(--ks-accent,#fbbf24));}
138
138
  .ksui-datatable-badge-danger{background:var(--ksui-dt-danger-bg,color-mix(in srgb, var(--ks-danger-fg, #f87171) 14%, transparent));color:var(--ksui-dt-danger,var(--ks-danger-fg,#f87171));}
@@ -118,6 +118,45 @@ describe("FlowGraph", () => {
118
118
  expect(canvas.getByTestId("c-svg").getAttribute("width")).toBe("100%");
119
119
  });
120
120
 
121
+ // Regression for a class-name-only token audit missing an attribute: the
122
+ // marker <path> fill and .ksui-fg-card background/border are SVG/CSS-in-JS
123
+ // strings, not Tailwind classes, so a scan that only greps class names for
124
+ // bare rgba()/hex literals walks right past them. jsdom doesn't compute
125
+ // SVG presentation-attribute styles, so this asserts on the rendered `fill`
126
+ // attribute plus the injected <style> source — both must route through the
127
+ // var(--ksui-fg-*/--ks-*) chain, never a bare rgba(255,255,255,...) literal.
128
+ it("routes the arrowhead marker fill and card background through CSS custom props, not a bare literal", async () => {
129
+ // injectCSS dedupes per-process (module-level Set in utils/inject-css),
130
+ // so a PRIOR test's render already consumed the injection — reset the
131
+ // module registry and re-import fresh so this test's render leaves an
132
+ // inspectable <style> tag regardless of suite order.
133
+ vi.resetModules();
134
+ const { default: FreshFlowGraph } = await import("./FlowGraph");
135
+
136
+ const { container } = render(() => (
137
+ <FreshFlowGraph
138
+ testId="fg"
139
+ nodes={[{ id: "a", label: "A" }, { id: "b", label: "B" }]}
140
+ edges={[{ from: "a", to: "b" }]}
141
+ />
142
+ ));
143
+
144
+ const markerPath = container.querySelector("marker#ksui-fg-arrow path");
145
+ const fill = markerPath?.getAttribute("fill") ?? "";
146
+ expect(fill).toMatch(/^var\(--ksui-fg-edge,/);
147
+ expect(fill).not.toMatch(/rgba\(\s*255\s*,\s*255\s*,\s*255/);
148
+
149
+ // jsdom can't compute SVG/CSS custom-property values, so assert on the
150
+ // injected <style> tag's rendered source instead of a computed style.
151
+ const styleEl = document.getElementById("ksui-flow-graph-style");
152
+ const css = styleEl?.textContent ?? "";
153
+ expect(css).toContain(".ksui-fg-card{");
154
+ const cardRule = css.slice(css.indexOf(".ksui-fg-card{"));
155
+ expect(cardRule).toMatch(/background:var\(--ksui-fg-card,/);
156
+ expect(cardRule).toMatch(/border:1px solid var\(--ksui-fg-node-border,/);
157
+ expect(css).not.toMatch(/rgba\(\s*255\s*,\s*255\s*,\s*255/);
158
+ });
159
+
121
160
  it("animates edges with the flow class only when animated", () => {
122
161
  const { container } = render(() => (
123
162
  <FlowGraph