slexkit 0.2.0 → 0.3.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.
Files changed (94) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +21 -21
  3. package/dist/ai/llms-authoring.txt +2 -0
  4. package/dist/ai/llms-capabilities.txt +126 -0
  5. package/dist/ai/llms-components.txt +27 -6
  6. package/dist/ai/llms-full.txt +1729 -4
  7. package/dist/ai/llms-runtime.txt +7 -1
  8. package/dist/ai/llms.txt +22 -1
  9. package/dist/ai/slexkit-ai-manifest.json +674 -23
  10. package/dist/base.css +359 -359
  11. package/dist/chunks/{accordion-cfjyxw93.js → button-53ccjq5p.js} +11 -11
  12. package/dist/chunks/{accordion-nw12ytps.js → button-cr1fhsa7.js} +48 -2
  13. package/dist/chunks/{accordion-5f0nvjjm.js → button-dsftwzvg.js} +4 -3
  14. package/dist/chunks/{accordion-hzyrngd6.js → button-faf563xf.js} +2 -2
  15. package/dist/chunks/{accordion-ehnhpeca.js → button-jxv4c65t.js} +2 -2
  16. package/dist/chunks/{accordion-cw5r75jm.js → button-xv2dz7vn.js} +1 -1
  17. package/dist/chunks/{accordion-830dw78f.js → button-z5yv24ks.js} +2 -2
  18. package/dist/components/accordion.js +2 -2
  19. package/dist/components/badge.js +2 -2
  20. package/dist/components/button.css +101 -101
  21. package/dist/components/button.js +3 -3
  22. package/dist/components/callout.js +4 -4
  23. package/dist/components/card.js +2 -2
  24. package/dist/components/checkbox.js +2 -2
  25. package/dist/components/choice.css +151 -151
  26. package/dist/components/code-block.js +2 -2
  27. package/dist/components/collapsible.js +2 -2
  28. package/dist/components/column.js +1 -1
  29. package/dist/components/content.css +273 -250
  30. package/dist/components/divider.js +2 -2
  31. package/dist/components/grid.js +1 -1
  32. package/dist/components/index.js +13945 -26
  33. package/dist/components/input.css +777 -777
  34. package/dist/components/input.js +8 -8
  35. package/dist/components/link.js +2 -2
  36. package/dist/components/progress.js +2 -2
  37. package/dist/components/radio-group.js +2 -2
  38. package/dist/components/row.js +1 -1
  39. package/dist/components/section.js +2 -2
  40. package/dist/components/select.css +178 -178
  41. package/dist/components/select.js +3 -3
  42. package/dist/components/slider.css +116 -116
  43. package/dist/components/slider.js +2 -2
  44. package/dist/components/specs.js +32 -0
  45. package/dist/components/stat.js +2 -2
  46. package/dist/components/submit.css +8 -8
  47. package/dist/components/submit.js +1 -1
  48. package/dist/components/switch.css +105 -105
  49. package/dist/components/switch.js +3 -3
  50. package/dist/components/table.js +4 -4
  51. package/dist/components/tabs.css +95 -95
  52. package/dist/components/tabs.js +4 -4
  53. package/dist/components/text-input.css +23 -23
  54. package/dist/components/text.js +1 -1
  55. package/dist/components/toast.js +4 -4
  56. package/dist/components/tooling.js +73 -8
  57. package/dist/runtime.cjs +1590 -14
  58. package/dist/runtime.js +1589 -13
  59. package/dist/slexkit.cjs +28254 -13848
  60. package/dist/slexkit.css +1538 -1515
  61. package/dist/slexkit.js +28253 -13847
  62. package/dist/tooling.js +117 -11
  63. package/dist/types/components/svelte/helpers.d.ts +8 -1
  64. package/dist/types/engine/capabilities.d.ts +54 -0
  65. package/dist/types/engine/index.d.ts +6 -0
  66. package/dist/types/engine/secure-runtime.d.ts +9 -1
  67. package/dist/types/engine/stdlib.d.ts +30 -0
  68. package/dist/types/engine/types.d.ts +1 -0
  69. package/dist/types/engine/validation.d.ts +28 -0
  70. package/dist/types/index.d.ts +6 -3
  71. package/dist/types/runtime.d.ts +6 -3
  72. package/dist/types/version.d.ts +2 -2
  73. package/dist/umd/slexkit.tooling.umd.js +45016 -44626
  74. package/dist/umd/slexkit.umd.js +28255 -13849
  75. package/package.json +3 -2
  76. package/src/components/svelte/content/Formula.svelte +27 -0
  77. package/src/components/svelte/content/Table.svelte +1 -1
  78. package/src/components/svelte/helpers.ts +56 -1
  79. package/src/components/svelte/input/Input.svelte +7 -7
  80. package/src/components/svelte/input/Select.svelte +2 -2
  81. package/src/components/svelte/input/Switch.svelte +1 -1
  82. package/src/components/svelte/input/Tabs.svelte +7 -7
  83. package/src/components/svelte/tooling/PlaygroundMarkdown.svelte +84 -2
  84. package/src/styles/components/button.css +101 -101
  85. package/src/styles/components/choice.css +152 -152
  86. package/src/styles/components/select.css +178 -178
  87. package/src/styles/components/slider.css +116 -116
  88. package/src/styles/components/submit.css +8 -8
  89. package/src/styles/components/switch.css +105 -105
  90. package/src/styles/components/tabs.css +95 -95
  91. package/src/styles/components/text-input.css +23 -23
  92. package/src/styles/content.css +274 -251
  93. package/src/styles/input.css +8 -8
  94. package/src/styles/layout.css +360 -360
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slexkit",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Zero-build, Markdown-friendly reactive UI runtime for AI output.",
5
5
  "author": "SlexKit contributors",
6
6
  "type": "module",
@@ -16,7 +16,7 @@
16
16
  "module": "./dist/slexkit.js",
17
17
  "types": "./dist/types/index.d.ts",
18
18
  "bin": {
19
- "slex": "./scripts/cli.mjs"
19
+ "slex": "scripts/cli.mjs"
20
20
  },
21
21
  "workspaces": [
22
22
  "packages/*"
@@ -92,6 +92,7 @@
92
92
  "copy-runtime": "node scripts/cli.mjs copy-runtime",
93
93
  "preview": "bun run site/server.ts",
94
94
  "smoke:release": "node scripts/release-smoke.mjs",
95
+ "smoke:registry": "node scripts/registry-smoke.mjs",
95
96
  "test": "bun test --conditions browser --isolate --preload ./tests/setup.ts tests packages",
96
97
  "test:watch": "bun test --conditions browser --isolate --watch --preload ./tests/setup.ts tests packages",
97
98
  "lint": "eslint src/",
@@ -0,0 +1,27 @@
1
+ <script lang="ts">
2
+ import katex from "katex";
3
+ import { bindPropStore } from "../bindProps";
4
+ import { bool, text } from "../helpers";
5
+ import type { PropValues, SvelteComponentProps } from "../types";
6
+
7
+ let { props }: SvelteComponentProps = $props();
8
+ let p = $state<PropValues>({});
9
+ $effect(() => bindPropStore(props, (next) => (p = next)));
10
+
11
+ const tex = $derived(text(p.tex ?? p.formula ?? p.value));
12
+ const displayMode = $derived(p.displayMode === undefined && p.display === undefined && p.block === undefined
13
+ ? true
14
+ : bool(p.displayMode ?? p.display ?? p.block));
15
+ const rendered = $derived(renderFormula(tex, displayMode));
16
+
17
+ function renderFormula(source: string, display: boolean): string {
18
+ return katex.renderToString(source || "\\,", {
19
+ displayMode: display,
20
+ throwOnError: false,
21
+ strict: "ignore",
22
+ output: "htmlAndMathml",
23
+ });
24
+ }
25
+ </script>
26
+
27
+ <div class="slex-formula" data-display={displayMode ? "block" : "inline"}>{@html rendered}</div>
@@ -31,7 +31,7 @@
31
31
  {#each rows(p.rows ?? p.items) as row}
32
32
  <tr>
33
33
  {#if readColumns(p.columns).length}
34
- {#each readColumns(p.columns) as column}<td>{readCell(row, column)}</td>{/each}
34
+ {#each readColumns(p.columns) as column, index}<td>{readCell(row, column, index)}</td>{/each}
35
35
  {:else if Array.isArray(row)}
36
36
  {#each row as cell}<td>{text(cell)}</td>{/each}
37
37
  {:else}
@@ -76,7 +76,8 @@ export function readColumnLabel(column: unknown, fallback: string): string {
76
76
  return text(column, fallback);
77
77
  }
78
78
 
79
- export function readCell(row: unknown, column: string): string {
79
+ export function readCell(row: unknown, column: string, index?: number): string {
80
+ if (Array.isArray(row)) return text(typeof index === "number" ? row[index] : undefined);
80
81
  if (row && typeof row === "object") return text((row as Record<string, unknown>)[column]);
81
82
  return text(row);
82
83
  }
@@ -105,6 +106,7 @@ export function catalogGroups(value: unknown): Array<{ label: string; items: Rec
105
106
 
106
107
  export function renderChildren(node: HTMLElement, ctx: RenderContext) {
107
108
  if (ctx.children && Object.keys(ctx.children).length > 0) {
109
+ node.replaceChildren();
108
110
  ctx.renderTree(ctx.children, node, ctx.forCtx);
109
111
  }
110
112
  return {
@@ -118,6 +120,59 @@ export function emit(ctx: RenderContext, event: string, data?: unknown): void {
118
120
  ctx.emit(event, data);
119
121
  }
120
122
 
123
+ export type ScheduledFrame = {
124
+ kind: "api" | "native" | "microtask";
125
+ id?: unknown;
126
+ canceled: boolean;
127
+ };
128
+
129
+ export function scheduleFrame(ctx: RenderContext, fn: (time?: number) => void): ScheduledFrame {
130
+ const handle: ScheduledFrame = { kind: "microtask", canceled: false };
131
+ const run = (time?: number) => {
132
+ if (!handle.canceled) fn(time);
133
+ };
134
+ const apiRaf = ctx.api?.raf;
135
+ if (typeof apiRaf === "function") {
136
+ try {
137
+ handle.kind = "api";
138
+ handle.id = apiRaf(run);
139
+ return handle;
140
+ } catch {
141
+ handle.kind = "microtask";
142
+ handle.id = undefined;
143
+ }
144
+ }
145
+
146
+ const ownerWindow = ctx.document.defaultView;
147
+ if (ownerWindow && typeof ownerWindow.requestAnimationFrame === "function") {
148
+ try {
149
+ handle.kind = "native";
150
+ handle.id = ownerWindow.requestAnimationFrame(run);
151
+ return handle;
152
+ } catch {
153
+ handle.kind = "microtask";
154
+ handle.id = undefined;
155
+ }
156
+ }
157
+
158
+ queueMicrotask(() => run());
159
+ return handle;
160
+ }
161
+
162
+ export function cancelScheduledFrame(ctx: RenderContext, handle: ScheduledFrame | undefined): void {
163
+ if (!handle || handle.canceled) return;
164
+ handle.canceled = true;
165
+ if (handle.kind === "api" && typeof ctx.api?.cancelRaf === "function") {
166
+ try {
167
+ ctx.api.cancelRaf(handle.id);
168
+ } catch {
169
+ // The runtime may already be disposed; cancellation is best effort.
170
+ }
171
+ } else if (handle.kind === "native" && typeof handle.id === "number") {
172
+ ctx.document.defaultView?.cancelAnimationFrame(handle.id);
173
+ }
174
+ }
175
+
121
176
  function formatScriptKey(key: string): string {
122
177
  return /^[A-Za-z_$][\w$]*$/.test(key) ? key : JSON.stringify(key);
123
178
  }
@@ -176,13 +176,6 @@
176
176
  {/if}
177
177
  {#if controls}
178
178
  <span class="slex-input-controls">
179
- <button
180
- class="slex-input-step"
181
- type="button"
182
- aria-label={`Decrease ${controlLabel}`}
183
- disabled={decrementDisabled}
184
- onclick={() => stepBy(-1)}
185
- >-</button>
186
179
  <button
187
180
  class="slex-input-step"
188
181
  type="button"
@@ -190,6 +183,13 @@
190
183
  disabled={incrementDisabled}
191
184
  onclick={() => stepBy(1)}
192
185
  >+</button>
186
+ <button
187
+ class="slex-input-step"
188
+ type="button"
189
+ aria-label={`Decrease ${controlLabel}`}
190
+ disabled={decrementDisabled}
191
+ onclick={() => stepBy(-1)}
192
+ >-</button>
193
193
  </span>
194
194
  {/if}
195
195
  </div>
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { onMount } from "svelte";
3
3
  import { bindPropStore } from "../bindProps";
4
- import { emit, label, list, text } from "../helpers";
4
+ import { emit, label, list, scheduleFrame, text } from "../helpers";
5
5
  import InlineIcon from "../InlineIcon.svelte";
6
6
  import type { PropValues, SvelteComponentProps } from "../types";
7
7
 
@@ -97,7 +97,7 @@
97
97
  function close(focusTrigger = true): void {
98
98
  open = false;
99
99
  activeIndex = selectedIndex();
100
- if (focusTrigger) requestAnimationFrame(() => triggerEl?.focus());
100
+ if (focusTrigger) scheduleFrame(ctx, () => triggerEl?.focus());
101
101
  }
102
102
 
103
103
  function toggle(): void {
@@ -10,7 +10,7 @@
10
10
  let lastHapticAt = 0;
11
11
  $effect(() => bindPropStore(props, (next) => {
12
12
  p = next;
13
- enabled = !!next.enabled;
13
+ enabled = !!(next.enabled ?? next.checked ?? next.value);
14
14
  }));
15
15
 
16
16
  function toggle(event: Event): void {
@@ -2,7 +2,7 @@
2
2
  import FlowbiteTabs from "../../../../node_modules/flowbite-svelte/dist/tabs/Tabs.svelte";
3
3
  import FlowbiteTabItem from "../../../../node_modules/flowbite-svelte/dist/tabs/TabItem.svelte";
4
4
  import { bindPropStore } from "../bindProps";
5
- import { emit, list, text } from "../helpers";
5
+ import { cancelScheduledFrame, emit, list, scheduleFrame, text, type ScheduledFrame } from "../helpers";
6
6
  import InlineIcon from "../InlineIcon.svelte";
7
7
  import type { PropValues, SvelteComponentProps } from "../types";
8
8
 
@@ -55,14 +55,14 @@
55
55
  }
56
56
 
57
57
  function annotateTabs(node: HTMLElement) {
58
- let raf: number | undefined;
58
+ let frame: ScheduledFrame | undefined;
59
59
  let resizeObserver: ResizeObserver | undefined;
60
60
  let indicatorReady = false;
61
61
 
62
62
  function scheduleIndicatorUpdate(list: HTMLElement, selectedTrigger: HTMLElement | undefined) {
63
- if (raf !== undefined) cancelAnimationFrame(raf);
64
- raf = requestAnimationFrame(() => {
65
- raf = undefined;
63
+ cancelScheduledFrame(ctx, frame);
64
+ frame = scheduleFrame(ctx, () => {
65
+ frame = undefined;
66
66
  if (!selectedTrigger) {
67
67
  list.style.setProperty("--slex-tabs-indicator-opacity", "0");
68
68
  return;
@@ -96,7 +96,7 @@
96
96
  list.style.setProperty("--slex-tabs-indicator-opacity", "1");
97
97
  if (!indicatorReady) {
98
98
  indicatorReady = true;
99
- requestAnimationFrame(() => {
99
+ scheduleFrame(ctx, () => {
100
100
  list.dataset.indicatorReady = "true";
101
101
  });
102
102
  }
@@ -137,7 +137,7 @@
137
137
  apply();
138
138
  },
139
139
  destroy() {
140
- if (raf !== undefined) cancelAnimationFrame(raf);
140
+ cancelScheduledFrame(ctx, frame);
141
141
  resizeObserver?.disconnect();
142
142
  },
143
143
  };
@@ -15,10 +15,92 @@
15
15
  inlineKatex: KatexRenderer,
16
16
  blockKatex: KatexRenderer,
17
17
  };
18
+ const options = { headerIds: false };
19
+
20
+ function stripFrontmatter(value: string) {
21
+ const raw = String(value ?? "").replace(/^\uFEFF/, "").replace(/\r\n/g, "\n");
22
+ if (!raw.startsWith("---")) return raw;
23
+
24
+ const end = raw.indexOf("\n---", 3);
25
+ if (end === -1) return raw;
26
+
27
+ const closeEnd = raw.indexOf("\n", end + 1);
28
+ return raw.slice(closeEnd === -1 ? raw.length : closeEnd + 1).trimStart();
29
+ }
30
+
31
+ function escapeHtml(value: string) {
32
+ return String(value)
33
+ .replace(/&/g, "&amp;")
34
+ .replace(/</g, "&lt;")
35
+ .replace(/>/g, "&gt;")
36
+ .replace(/"/g, "&quot;");
37
+ }
38
+
39
+ function stripInlineMarkdown(value: string) {
40
+ return String(value)
41
+ .replace(/\s+\{#[A-Za-z0-9_-]+\}\s*$/, "")
42
+ .replace(/`([^`]+)`/g, "$1")
43
+ .replace(/\*\*([^*]+)\*\*/g, "$1")
44
+ .replace(/\*([^*]+)\*/g, "$1")
45
+ .replace(/\[([^\]]+)\]\([^)]+\)/g, "$1")
46
+ .replace(/<[^>]+>/g, "")
47
+ .replace(/\s+#+\s*$/, "")
48
+ .trim();
49
+ }
50
+
51
+ function slugText(value: string) {
52
+ const slug = String(value)
53
+ .toLowerCase()
54
+ .replace(/[`"'\u2018\u2019\u201c\u201d]/g, "")
55
+ .replace(/[^a-z0-9\u4e00-\u9fa5]+/g, "-")
56
+ .replace(/^-+|-+$/g, "");
57
+ return slug || "section";
58
+ }
59
+
60
+ function createHeadingIdGenerator() {
61
+ const counts = new Map<string, number>();
62
+ return (rawTitle: string) => {
63
+ const explicit = rawTitle.match(/\s+\{#([A-Za-z0-9_-]+)\}\s*$/)?.[1] ?? "";
64
+ const base = explicit || slugText(stripInlineMarkdown(rawTitle));
65
+ const count = counts.get(base) ?? 0;
66
+ counts.set(base, count + 1);
67
+ return count ? `${base}-${count + 1}` : base;
68
+ };
69
+ }
70
+
71
+ function normalizeHeadingAnchors(markdown: string) {
72
+ const nextId = createHeadingIdGenerator();
73
+ let fence: { char: string; length: number } | null = null;
74
+
75
+ return String(markdown ?? "")
76
+ .split(/\n/)
77
+ .map((line) => {
78
+ const marker = String(line).match(/^[ \t]{0,3}(`{3,}|~{3,})/);
79
+ if (fence) {
80
+ if (marker && marker[1][0] === fence.char && marker[1].length >= fence.length) fence = null;
81
+ return line;
82
+ }
83
+ if (marker) {
84
+ fence = { char: marker[1][0], length: marker[1].length };
85
+ return line;
86
+ }
87
+
88
+ const heading = String(line).match(/^(#{1,6})[ \t]+(.+)$/);
89
+ if (!heading) return line;
90
+ const rawTitle = heading[2].replace(/\s+#+\s*$/, "");
91
+ const renderedTitle = rawTitle.replace(/\s+\{#[A-Za-z0-9_-]+\}\s*$/, "").trim();
92
+ return `<span id="${escapeHtml(nextId(rawTitle))}" class="slex-doc-heading-anchor"></span>\n${heading[1]} ${renderedTitle}`;
93
+ })
94
+ .join("\n");
95
+ }
96
+
97
+ function previewMarkdown(value: string) {
98
+ return normalizeHeadingAnchors(stripFrontmatter(value));
99
+ }
18
100
  </script>
19
101
 
20
- <div class="slex-doc-streamdown">
21
- <SvelteMarkdown source={content} {extensions} {renderers}>
102
+ <div class="slex-doc-prose slex-doc-streamdown">
103
+ <SvelteMarkdown source={previewMarkdown(content)} {extensions} {renderers} {options}>
22
104
  {#snippet code({ lang, text })}
23
105
  <PlaygroundSlexCode {lang} {text} {domain} />
24
106
  {/snippet}
@@ -1,104 +1,104 @@
1
- .slex-button {
2
- display: inline-flex;
3
- align-items: center;
4
- justify-content: center;
5
- gap: 0.5rem;
6
- max-width: 100%;
7
- min-width: 0;
8
- padding: 0.5rem 1rem;
9
- border: 1px solid transparent;
10
- border-radius: var(--radius);
11
- font-family: inherit;
12
- font-size: 0.875rem;
13
- font-weight: 500;
14
- line-height: 1.25;
15
- white-space: nowrap;
16
- text-overflow: ellipsis;
17
- overflow: hidden;
18
- cursor: pointer;
19
- user-select: none;
20
- transition:
21
- background 150ms ease,
22
- border-color 150ms ease,
23
- color 150ms ease,
24
- box-shadow 150ms ease,
25
- transform 150ms ease;
26
- }
27
-
28
- .slex-button--primary {
29
- background: var(--primary);
30
- color: var(--primary-foreground);
31
- border-color: var(--primary);
32
- }
33
-
34
- .slex-button--primary:hover:not(:disabled):not(.slex-button--disabled) {
35
- background: color-mix(in oklab, var(--primary) 90%, transparent);
36
- border-color: color-mix(in oklab, var(--primary) 90%, transparent);
37
- color: var(--primary-foreground);
38
- transform: translateY(-1px);
39
- box-shadow: var(--shadow-md);
40
- }
41
-
42
- .slex-button--secondary {
43
- background: var(--secondary);
44
- color: var(--secondary-foreground);
45
- border-color: var(--border);
46
- }
47
-
48
- .slex-button--secondary:hover:not(:disabled):not(.slex-button--disabled) {
49
- background: var(--accent);
50
- color: var(--accent-foreground);
51
- border-color: var(--border);
52
- }
53
-
54
- .slex-button--danger {
55
- background: var(--destructive);
56
- color: var(--destructive-foreground);
57
- border-color: var(--destructive);
58
- }
59
-
60
- .slex-button--danger:hover:not(:disabled):not(.slex-button--disabled) {
61
- background: color-mix(in oklab, var(--destructive) 90%, transparent);
62
- border-color: color-mix(in oklab, var(--destructive) 90%, transparent);
63
- }
64
-
65
- .slex-button--ghost {
66
- background: transparent;
67
- color: var(--muted-foreground);
68
- border-color: transparent;
69
- }
70
-
71
- .slex-button--ghost:hover:not(:disabled):not(.slex-button--disabled) {
72
- background: var(--accent);
73
- color: var(--accent-foreground);
74
- }
75
-
76
- .slex-button:disabled,
77
- .slex-button[disabled],
78
- .slex-button--disabled {
79
- opacity: 0.5;
80
- cursor: not-allowed;
81
- pointer-events: none;
82
- transform: none;
83
- box-shadow: none;
84
- }
85
-
86
- .slex-button:active:not(:disabled):not(.slex-button--disabled) {
87
- transform: translateY(0);
88
- box-shadow: var(--shadow-sm);
89
- }
90
-
91
- .slex-button:focus-visible {
92
- outline: 2px solid var(--ring);
93
- outline-offset: 2px;
94
- }
95
-
96
- .slex-button--icon {
97
- width: var(--slex-control-height, 2.25rem);
98
- min-height: var(--slex-control-height, 2.25rem);
99
- padding-inline: 0;
100
- }
101
-
1
+ .slex-button {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ gap: 0.5rem;
6
+ max-width: 100%;
7
+ min-width: 0;
8
+ padding: 0.5rem 1rem;
9
+ border: 1px solid transparent;
10
+ border-radius: var(--radius);
11
+ font-family: inherit;
12
+ font-size: 0.875rem;
13
+ font-weight: 500;
14
+ line-height: 1.25;
15
+ white-space: nowrap;
16
+ text-overflow: ellipsis;
17
+ overflow: hidden;
18
+ cursor: pointer;
19
+ user-select: none;
20
+ transition:
21
+ background 150ms ease,
22
+ border-color 150ms ease,
23
+ color 150ms ease,
24
+ box-shadow 150ms ease,
25
+ transform 150ms ease;
26
+ }
27
+
28
+ .slex-button--primary {
29
+ background: var(--primary);
30
+ color: var(--primary-foreground);
31
+ border-color: var(--primary);
32
+ }
33
+
34
+ .slex-button--primary:hover:not(:disabled):not(.slex-button--disabled) {
35
+ background: color-mix(in oklab, var(--primary) 90%, transparent);
36
+ border-color: color-mix(in oklab, var(--primary) 90%, transparent);
37
+ color: var(--primary-foreground);
38
+ transform: translateY(-1px);
39
+ box-shadow: var(--shadow-md);
40
+ }
41
+
42
+ .slex-button--secondary {
43
+ background: var(--secondary);
44
+ color: var(--secondary-foreground);
45
+ border-color: var(--border);
46
+ }
47
+
48
+ .slex-button--secondary:hover:not(:disabled):not(.slex-button--disabled) {
49
+ background: var(--accent);
50
+ color: var(--accent-foreground);
51
+ border-color: var(--border);
52
+ }
53
+
54
+ .slex-button--danger {
55
+ background: var(--destructive);
56
+ color: var(--destructive-foreground);
57
+ border-color: var(--destructive);
58
+ }
59
+
60
+ .slex-button--danger:hover:not(:disabled):not(.slex-button--disabled) {
61
+ background: color-mix(in oklab, var(--destructive) 90%, transparent);
62
+ border-color: color-mix(in oklab, var(--destructive) 90%, transparent);
63
+ }
64
+
65
+ .slex-button--ghost {
66
+ background: transparent;
67
+ color: var(--muted-foreground);
68
+ border-color: transparent;
69
+ }
70
+
71
+ .slex-button--ghost:hover:not(:disabled):not(.slex-button--disabled) {
72
+ background: var(--accent);
73
+ color: var(--accent-foreground);
74
+ }
75
+
76
+ .slex-button:disabled,
77
+ .slex-button[disabled],
78
+ .slex-button--disabled {
79
+ opacity: 0.5;
80
+ cursor: not-allowed;
81
+ pointer-events: none;
82
+ transform: none;
83
+ box-shadow: none;
84
+ }
85
+
86
+ .slex-button:active:not(:disabled):not(.slex-button--disabled) {
87
+ transform: translateY(0);
88
+ box-shadow: var(--shadow-sm);
89
+ }
90
+
91
+ .slex-button:focus-visible {
92
+ outline: 2px solid var(--ring);
93
+ outline-offset: 2px;
94
+ }
95
+
96
+ .slex-button--icon {
97
+ width: var(--slex-control-height, 2.25rem);
98
+ min-height: var(--slex-control-height, 2.25rem);
99
+ padding-inline: 0;
100
+ }
101
+
102
102
  .slex-button-icon {
103
103
  display: inline-flex;
104
104
  width: 1.125rem;