@codeauradev/ngx-wind-editor 1.0.0 → 1.0.2

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.
@@ -1,6 +1,6 @@
1
1
  import * as Y from "yjs";
2
2
  import * as i0 from "@angular/core";
3
- import { ChangeDetectionStrategy, Component, DestroyRef, ViewEncapsulation, afterNextRender, computed, effect, inject, input, model, signal, viewChild } from "@angular/core";
3
+ import { ChangeDetectionStrategy, Component, DestroyRef, ViewEncapsulation, afterNextRender, computed, effect, inject, input, model, output, signal, viewChild } from "@angular/core";
4
4
  const SLASH_ITEMS = [
5
5
  {
6
6
  id: "paragraph",
@@ -1799,8 +1799,8 @@ function mountWindSurface(host, options) {
1799
1799
  unsession();
1800
1800
  frame.replaceChildren();
1801
1801
  },
1802
- focus() {
1803
- docEl.focus();
1802
+ focus(options) {
1803
+ docEl.focus(options);
1804
1804
  },
1805
1805
  exec(command) {
1806
1806
  if (readonly && command.type !== "undo" && command.type !== "redo") return;
@@ -2032,12 +2032,16 @@ const TOOLS = [
2032
2032
  ];
2033
2033
  var WindEditor = class WindEditor {
2034
2034
  constructor() {
2035
+ this.value = model("", ...ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []);
2035
2036
  this.html = model("", ...ngDevMode ? [{ debugName: "html" }] : /* istanbul ignore next */ []);
2036
2037
  this.placeholder = input("Write something…", ...ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []);
2037
- this.readOnly = input(false, {
2038
- ...ngDevMode ? { debugName: "readOnly" } : /* istanbul ignore next */ {},
2039
- alias: "readonly"
2040
- });
2038
+ this.readonly = input(false, ...ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []);
2039
+ this.disabled = input(false, ...ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []);
2040
+ this.invalid = input(false, ...ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []);
2041
+ this.required = input(false, ...ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []);
2042
+ this.touched = input(false, ...ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []);
2043
+ this.errors = input([], ...ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []);
2044
+ this.touch = output();
2041
2045
  this.showToolbar = input(true, ...ngDevMode ? [{ debugName: "showToolbar" }] : /* istanbul ignore next */ []);
2042
2046
  this.toolbar = input("full", ...ngDevMode ? [{ debugName: "toolbar" }] : /* istanbul ignore next */ []);
2043
2047
  this.tools = computed(() => {
@@ -2056,6 +2060,7 @@ var WindEditor = class WindEditor {
2056
2060
  this.sourceOpen = signal(false, ...ngDevMode ? [{ debugName: "sourceOpen" }] : /* istanbul ignore next */ []);
2057
2061
  this.sourceDraft = signal("", ...ngDevMode ? [{ debugName: "sourceDraft" }] : /* istanbul ignore next */ []);
2058
2062
  this.slashIndex = signal(0, ...ngDevMode ? [{ debugName: "slashIndex" }] : /* istanbul ignore next */ []);
2063
+ this.errorText = computed(() => this.errors().map((error) => error.message || error.kind).filter((message) => message.length > 0).join(" "), ...ngDevMode ? [{ debugName: "errorText" }] : /* istanbul ignore next */ []);
2059
2064
  this.slashItems = computed(() => {
2060
2065
  const query = this.change()?.slash;
2061
2066
  return query === null || query === void 0 ? [] : filterSlash(query);
@@ -2065,15 +2070,23 @@ var WindEditor = class WindEditor {
2065
2070
  this.handle = null;
2066
2071
  this.echo = "";
2067
2072
  afterNextRender(() => this.attach());
2073
+ effect(() => {
2074
+ const next = this.html();
2075
+ if (next !== this.value()) this.value.set(next);
2076
+ });
2077
+ effect(() => {
2078
+ const next = this.value();
2079
+ if (next !== this.html()) this.html.set(next);
2080
+ });
2068
2081
  effect(() => {
2069
2082
  const value = this.placeholder();
2070
2083
  this.handle?.setPlaceholder(value);
2071
2084
  });
2072
2085
  effect(() => {
2073
- this.handle?.setReadonly(this.readOnly());
2086
+ this.handle?.setReadonly(this.readonly() || this.disabled());
2074
2087
  });
2075
2088
  effect(() => {
2076
- const html = this.html();
2089
+ const html = this.value();
2077
2090
  if (html !== this.echo) this.handle?.setHtml(html);
2078
2091
  });
2079
2092
  effect(() => {
@@ -2098,8 +2111,8 @@ var WindEditor = class WindEditor {
2098
2111
  if (id === "source") return this.sourceOpen();
2099
2112
  return false;
2100
2113
  }
2101
- disabled(id) {
2102
- if (this.readOnly() && id !== "source") return true;
2114
+ toolDisabled(id) {
2115
+ if ((this.readonly() || this.disabled()) && id !== "source") return true;
2103
2116
  const snap = this.change();
2104
2117
  if (id === "undo") return !snap?.canUndo;
2105
2118
  if (id === "redo") return !snap?.canRedo;
@@ -2147,7 +2160,7 @@ var WindEditor = class WindEditor {
2147
2160
  this.linkOpen.update((open) => !open);
2148
2161
  } else if (id === "image") this.imageOpen.update((open) => !open);
2149
2162
  else if (id === "source") {
2150
- this.sourceDraft.set(this.change()?.html ?? this.html());
2163
+ this.sourceDraft.set(this.change()?.html ?? this.value());
2151
2164
  this.sourceOpen.update((open) => !open);
2152
2165
  }
2153
2166
  }
@@ -2195,7 +2208,7 @@ var WindEditor = class WindEditor {
2195
2208
  }
2196
2209
  applySource() {
2197
2210
  this.echo = this.sourceDraft();
2198
- this.html.set(this.echo);
2211
+ this.value.set(this.echo);
2199
2212
  this.handle?.setHtml(this.echo);
2200
2213
  this.sourceOpen.set(false);
2201
2214
  }
@@ -2210,14 +2223,14 @@ var WindEditor = class WindEditor {
2210
2223
  const element = this.surfaceRef()?.nativeElement;
2211
2224
  if (!element || this.handle) return;
2212
2225
  this.handle = mountWindSurface(element, {
2213
- html: this.html() || void 0,
2226
+ html: this.value() || void 0,
2214
2227
  placeholder: this.placeholder(),
2215
- readonly: this.readOnly(),
2228
+ readonly: this.readonly() || this.disabled(),
2216
2229
  onChange: (change) => {
2217
2230
  this.change.set(change);
2218
- if (change.html !== this.html()) {
2231
+ if (change.html !== this.value()) {
2219
2232
  this.echo = change.html;
2220
- this.html.set(change.html);
2233
+ this.value.set(change.html);
2221
2234
  }
2222
2235
  },
2223
2236
  onLink: () => {
@@ -2227,7 +2240,15 @@ var WindEditor = class WindEditor {
2227
2240
  interceptKey: (event) => this.onKey(event)
2228
2241
  });
2229
2242
  this.echo = this.handle.getHtml();
2230
- if (this.echo !== this.html()) this.html.set(this.echo);
2243
+ if (this.echo !== this.value()) this.value.set(this.echo);
2244
+ }
2245
+ focus(options) {
2246
+ this.handle?.focus(options);
2247
+ }
2248
+ onFocusOut(event) {
2249
+ const next = event.relatedTarget;
2250
+ if (next instanceof Node && event.currentTarget instanceof Node && event.currentTarget.contains(next)) return;
2251
+ this.touch.emit();
2231
2252
  }
2232
2253
  onKey(event) {
2233
2254
  const items = this.slashItems();
@@ -2273,6 +2294,13 @@ var WindEditor = class WindEditor {
2273
2294
  isStandalone: true,
2274
2295
  selector: "wind-editor",
2275
2296
  inputs: {
2297
+ value: {
2298
+ classPropertyName: "value",
2299
+ publicName: "value",
2300
+ isSignal: true,
2301
+ isRequired: false,
2302
+ transformFunction: null
2303
+ },
2276
2304
  html: {
2277
2305
  classPropertyName: "html",
2278
2306
  publicName: "html",
@@ -2287,13 +2315,48 @@ var WindEditor = class WindEditor {
2287
2315
  isRequired: false,
2288
2316
  transformFunction: null
2289
2317
  },
2290
- readOnly: {
2291
- classPropertyName: "readOnly",
2318
+ readonly: {
2319
+ classPropertyName: "readonly",
2292
2320
  publicName: "readonly",
2293
2321
  isSignal: true,
2294
2322
  isRequired: false,
2295
2323
  transformFunction: null
2296
2324
  },
2325
+ disabled: {
2326
+ classPropertyName: "disabled",
2327
+ publicName: "disabled",
2328
+ isSignal: true,
2329
+ isRequired: false,
2330
+ transformFunction: null
2331
+ },
2332
+ invalid: {
2333
+ classPropertyName: "invalid",
2334
+ publicName: "invalid",
2335
+ isSignal: true,
2336
+ isRequired: false,
2337
+ transformFunction: null
2338
+ },
2339
+ required: {
2340
+ classPropertyName: "required",
2341
+ publicName: "required",
2342
+ isSignal: true,
2343
+ isRequired: false,
2344
+ transformFunction: null
2345
+ },
2346
+ touched: {
2347
+ classPropertyName: "touched",
2348
+ publicName: "touched",
2349
+ isSignal: true,
2350
+ isRequired: false,
2351
+ transformFunction: null
2352
+ },
2353
+ errors: {
2354
+ classPropertyName: "errors",
2355
+ publicName: "errors",
2356
+ isSignal: true,
2357
+ isRequired: false,
2358
+ transformFunction: null
2359
+ },
2297
2360
  showToolbar: {
2298
2361
  classPropertyName: "showToolbar",
2299
2362
  publicName: "showToolbar",
@@ -2309,8 +2372,22 @@ var WindEditor = class WindEditor {
2309
2372
  transformFunction: null
2310
2373
  }
2311
2374
  },
2312
- outputs: { html: "htmlChange" },
2313
- host: { classAttribute: "wind-editor block min-w-0" },
2375
+ outputs: {
2376
+ value: "valueChange",
2377
+ html: "htmlChange",
2378
+ touch: "touch"
2379
+ },
2380
+ host: {
2381
+ listeners: { "focusout": "onFocusOut($event)" },
2382
+ properties: {
2383
+ "class.is-invalid": "invalid()",
2384
+ "class.is-disabled": "disabled()",
2385
+ "attr.aria-invalid": "invalid() || null",
2386
+ "attr.aria-required": "required() || null",
2387
+ "attr.aria-disabled": "disabled() || null"
2388
+ },
2389
+ classAttribute: "wind-editor"
2390
+ },
2314
2391
  viewQueries: [{
2315
2392
  propertyName: "surfaceRef",
2316
2393
  first: true,
@@ -2320,22 +2397,22 @@ var WindEditor = class WindEditor {
2320
2397
  }],
2321
2398
  ngImport: i0,
2322
2399
  template: `
2323
- <div class="rounded-xl border border-stone-200 bg-white text-stone-900 shadow-sm dark:border-stone-800 dark:bg-stone-950 dark:text-stone-100">
2400
+ <div class="wind-shell">
2324
2401
  @if (showToolbar() && tools().length > 0) {
2325
- <div class="flex gap-0.5 overflow-x-auto border-b border-stone-200 px-1.5 py-1.5 dark:border-stone-800" role="toolbar" aria-label="Formatting">
2402
+ <div class="wind-toolbar" role="toolbar" aria-label="Formatting">
2326
2403
  @for (tool of tools(); track tool.id) {
2327
2404
  <button
2328
2405
  type="button"
2329
- class="inline-flex h-9 shrink-0 items-center justify-center gap-1 rounded-md px-2 text-sm text-stone-600 hover:bg-stone-100 disabled:opacity-40 aria-pressed:bg-teal-700 aria-pressed:text-white dark:text-stone-300 dark:hover:bg-stone-900 dark:aria-pressed:bg-teal-600"
2406
+ class="wind-tool"
2330
2407
  [attr.aria-label]="tool.label"
2331
2408
  [attr.title]="tool.label"
2332
2409
  [attr.aria-pressed]="pressed(tool.id)"
2333
- [disabled]="disabled(tool.id)"
2410
+ [disabled]="toolDisabled(tool.id)"
2334
2411
  (mousedown)="$event.preventDefault()"
2335
2412
  (click)="run(tool.id)"
2336
2413
  >
2337
2414
  @if (tool.id === 'paragraph' || tool.id === 'h1' || tool.id === 'h2') {
2338
- <span class="px-0.5 text-xs font-semibold tracking-wide">{{ tool.id === 'paragraph' ? 'P' : tool.id.toUpperCase() }}</span>
2415
+ <span class="wind-tool-label">{{ tool.id === 'paragraph' ? 'P' : tool.id.toUpperCase() }}</span>
2339
2416
  } @else {
2340
2417
  <wind-icon [name]="tool.icon" />
2341
2418
  }
@@ -2345,33 +2422,33 @@ var WindEditor = class WindEditor {
2345
2422
  }
2346
2423
 
2347
2424
  @if (linkOpen()) {
2348
- <form class="flex flex-wrap items-center gap-2 border-b border-stone-200 px-3 py-2 dark:border-stone-800" (submit)="applyLink($event)">
2349
- <label class="sr-only" for="wind-link">Link URL</label>
2425
+ <form class="wind-pop" (submit)="applyLink($event)">
2426
+ <label class="wind-sr" for="wind-link">Link URL</label>
2350
2427
  <input
2351
2428
  id="wind-link"
2352
- class="h-9 min-w-0 flex-1 rounded-md border border-stone-300 bg-white px-2 text-sm outline-none focus:border-teal-700 dark:border-stone-700 dark:bg-stone-900"
2429
+ class="wind-field"
2353
2430
  [value]="linkDraft()"
2354
2431
  placeholder="https://"
2355
2432
  (input)="onDraft($event, 'link')"
2356
2433
  />
2357
- <button type="submit" class="h-9 rounded-md bg-teal-700 px-3 text-sm font-medium text-white">Apply</button>
2358
- <button type="button" class="h-9 rounded-md px-2 text-sm text-stone-600 dark:text-stone-300" (click)="clearLink()">Remove</button>
2434
+ <button type="submit" class="wind-primary">Apply</button>
2435
+ <button type="button" class="wind-quiet" (click)="clearLink()">Remove</button>
2359
2436
  </form>
2360
2437
  }
2361
2438
 
2362
2439
  @if (imageOpen()) {
2363
- <form class="flex flex-wrap items-center gap-2 border-b border-stone-200 px-3 py-2 dark:border-stone-800" (submit)="applyImage($event)">
2364
- <input class="h-9 min-w-0 flex-1 rounded-md border border-stone-300 bg-white px-2 text-sm outline-none focus:border-teal-700 dark:border-stone-700 dark:bg-stone-900" [value]="imageSrc()" placeholder="Image URL" (input)="onDraft($event, 'src')" />
2365
- <input class="h-9 w-36 rounded-md border border-stone-300 bg-white px-2 text-sm outline-none focus:border-teal-700 dark:border-stone-700 dark:bg-stone-900" [value]="imageAlt()" placeholder="Alt text" (input)="onDraft($event, 'alt')" />
2366
- <button type="submit" class="h-9 rounded-md bg-teal-700 px-3 text-sm font-medium text-white">Insert</button>
2440
+ <form class="wind-pop" (submit)="applyImage($event)">
2441
+ <input class="wind-field" [value]="imageSrc()" placeholder="Image URL" (input)="onDraft($event, 'src')" />
2442
+ <input class="wind-field wind-field-short" [value]="imageAlt()" placeholder="Alt text" (input)="onDraft($event, 'alt')" />
2443
+ <button type="submit" class="wind-primary">Insert</button>
2367
2444
  </form>
2368
2445
  }
2369
2446
 
2370
- <div class="relative min-h-48" #surface></div>
2447
+ <div class="wind-surface" #surface></div>
2371
2448
 
2372
2449
  @if (slashItems().length > 0 && change()?.slashRect; as rect) {
2373
2450
  <ul
2374
- class="fixed z-30 max-h-64 w-56 overflow-auto rounded-lg border border-stone-200 bg-white py-1 shadow-lg dark:border-stone-700 dark:bg-stone-900"
2451
+ class="wind-menu"
2375
2452
  role="listbox"
2376
2453
  [style.top.px]="rect.top"
2377
2454
  [style.left.px]="rect.left"
@@ -2380,43 +2457,46 @@ var WindEditor = class WindEditor {
2380
2457
  <li>
2381
2458
  <button
2382
2459
  type="button"
2383
- class="flex w-full items-baseline justify-between gap-3 px-3 py-1.5 text-left text-sm hover:bg-stone-100 dark:hover:bg-stone-800"
2384
- [class.bg-teal-700]="index === slashIndex()"
2385
- [class.text-white]="index === slashIndex()"
2460
+ class="wind-option"
2461
+ [class.is-active]="index === slashIndex()"
2386
2462
  role="option"
2387
2463
  [attr.aria-selected]="index === slashIndex()"
2388
2464
  (mousedown)="$event.preventDefault()"
2389
2465
  (click)="pickSlash(item)"
2390
2466
  >
2391
2467
  <span>{{ item.label }}</span>
2392
- <span class="text-xs opacity-70">{{ item.hint }}</span>
2468
+ <span class="wind-option-hint">{{ item.hint }}</span>
2393
2469
  </button>
2394
2470
  </li>
2395
2471
  }
2396
2472
  </ul>
2397
2473
  }
2398
2474
 
2399
- <footer class="flex items-center justify-between gap-3 border-t border-stone-200 px-3 py-1.5 text-xs text-stone-500 dark:border-stone-800 dark:text-stone-400">
2475
+ <footer class="wind-meta">
2400
2476
  <span>{{ change()?.words ?? 0 }} words</span>
2401
- <span class="text-stone-400">/ for blocks</span>
2477
+ <span class="wind-meta-hint">/ for blocks</span>
2402
2478
  </footer>
2403
2479
 
2480
+ @if (invalid() && errorText()) {
2481
+ <p class="wind-error" role="alert">{{ errorText() }}</p>
2482
+ }
2483
+
2404
2484
  @if (sourceOpen()) {
2405
- <div class="border-t border-stone-200 p-3 dark:border-stone-800">
2485
+ <div class="wind-source">
2406
2486
  <textarea
2407
- class="h-40 w-full resize-y rounded-md border border-stone-300 bg-stone-50 p-2 font-mono text-xs outline-none focus:border-teal-700 dark:border-stone-700 dark:bg-stone-900"
2487
+ class="wind-source-input"
2408
2488
  [value]="sourceDraft()"
2409
2489
  spellcheck="false"
2410
2490
  aria-label="HTML source"
2411
2491
  (input)="onDraft($event, 'source')"
2412
2492
  ></textarea>
2413
- <button type="button" class="mt-2 h-9 rounded-md bg-stone-900 px-3 text-sm text-white dark:bg-stone-100 dark:text-stone-900" (click)="applySource()">Apply HTML</button>
2493
+ <button type="button" class="wind-primary" (click)="applySource()">Apply HTML</button>
2414
2494
  </div>
2415
2495
  }
2416
2496
  </div>
2417
2497
  `,
2418
2498
  isInline: true,
2419
- styles: [":host{display:block;min-width:0}.wind-frame{position:relative;min-width:0}.wind-doc{min-height:12rem;padding:1rem 1.15rem 1.5rem;outline:none;color:var(--color-stone-900, #1c1917);font-family:var(--font-serif, Georgia, \"Iowan Old Style\", \"Palatino Linotype\", serif);font-size:1.0625rem;line-height:1.65;caret-color:var(--color-teal-700, #0f766e);overflow-wrap:anywhere}.wind-doc>*+*{margin-top:.75rem}.wind-doc p,.wind-doc h1,.wind-doc h2,.wind-doc h3,.wind-doc blockquote,.wind-doc pre,.wind-doc li{margin:0}.wind-doc h1,.wind-doc h2,.wind-doc h3{font-family:var(--font-sans, ui-sans-serif, system-ui, sans-serif);line-height:1.2;letter-spacing:-.03em;color:var(--color-stone-950, #0c0a09)}.wind-doc h1{font-size:1.875rem;font-weight:600}.wind-doc h2{font-size:1.5rem;font-weight:600}.wind-doc h3{font-size:1.25rem;font-weight:600}.wind-doc blockquote{border-left:2px solid var(--color-teal-700, #0f766e);padding-left:.9rem;color:var(--color-stone-600, #57534e)}.wind-doc ul,.wind-doc ol{margin:0;padding-left:1.25rem}.wind-doc li+li{margin-top:.25rem}.wind-doc pre{overflow-x:auto;border-radius:.6rem;background:color-mix(in oklab,var(--color-stone-900, #1c1917) 6%,transparent);padding:.8rem .9rem;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.875rem;line-height:1.55;white-space:pre-wrap}.wind-doc pre code{font:inherit;background:none;padding:0}.wind-doc a{color:var(--color-teal-800, #115e59);text-decoration:underline;text-underline-offset:2px}.wind-doc code{border-radius:.3rem;background:color-mix(in oklab,var(--color-stone-900, #1c1917) 8%,transparent);padding:.05em .3em;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.88em}.wind-doc img{display:block;max-width:100%;border-radius:.6rem}.wind-doc figure{margin:0}.wind-doc hr{border:0;border-top:1px solid var(--color-stone-300, #d6d3d1);margin:.25rem 0}.wind-doc [data-atomic].is-selected{outline:2px solid var(--color-teal-700, #0f766e);outline-offset:3px;border-radius:.4rem}.wind-doc[data-empty=true]>p[data-placeholder]:before{content:attr(data-placeholder);float:left;height:0;pointer-events:none;color:var(--color-stone-400, #a8a29e)}.wind-carets{position:absolute;inset:0;pointer-events:none;overflow:hidden}.wind-caret,.wind-remote{position:absolute;pointer-events:none}.wind-caret{width:2px;background:var(--peer);border-radius:1px}.wind-caret i{position:absolute;top:-1.15rem;left:-1px;border-radius:.3rem;background:var(--peer);color:#fff;padding:.05rem .3rem;font-family:var(--font-sans, ui-sans-serif, system-ui, sans-serif);font-size:.65rem;font-style:normal;line-height:1.3;letter-spacing:.01em;white-space:nowrap}.wind-remote{background:color-mix(in oklab,var(--peer) 32%,transparent);border-radius:.1rem}.wind-frame.is-readonly .wind-doc{caret-color:transparent}.dark .wind-doc{color:var(--color-stone-100, #f5f5f4);caret-color:var(--color-teal-300, #5eead4)}.dark .wind-doc h1,.dark .wind-doc h2,.dark .wind-doc h3{color:var(--color-stone-50, #fafaf9)}.dark .wind-doc blockquote{color:var(--color-stone-400, #a8a29e)}.dark .wind-doc a{color:var(--color-teal-300, #5eead4)}.dark .wind-doc hr{border-top-color:var(--color-stone-700, #44403c)}.dark .wind-doc pre,.dark .wind-doc code{background:color-mix(in oklab,white 8%,transparent)}\n"],
2499
+ styles: ["wind-editor,.wind-editor{display:block;min-width:0;color:#1c1917;font-family:var(--font-sans, ui-sans-serif, system-ui, sans-serif)}.wind-frame{position:relative;min-width:0}.wind-doc{min-height:12rem;padding:1rem 1.15rem 1.5rem;outline:none;color:var(--color-stone-900, #1c1917);font-family:var(--font-serif, Georgia, \"Iowan Old Style\", \"Palatino Linotype\", serif);font-size:1.0625rem;line-height:1.65;caret-color:var(--color-teal-700, #0f766e);overflow-wrap:anywhere}.wind-doc>*+*{margin-top:.75rem}.wind-doc p,.wind-doc h1,.wind-doc h2,.wind-doc h3,.wind-doc blockquote,.wind-doc pre,.wind-doc li{margin:0}.wind-doc h1,.wind-doc h2,.wind-doc h3{font-family:var(--font-sans, ui-sans-serif, system-ui, sans-serif);line-height:1.2;letter-spacing:-.03em;color:var(--color-stone-950, #0c0a09)}.wind-doc h1{font-size:1.875rem;font-weight:600}.wind-doc h2{font-size:1.5rem;font-weight:600}.wind-doc h3{font-size:1.25rem;font-weight:600}.wind-doc blockquote{border-left:2px solid var(--color-teal-700, #0f766e);padding-left:.9rem;color:var(--color-stone-600, #57534e)}.wind-doc ul,.wind-doc ol{margin:0;padding-left:1.25rem}.wind-doc li+li{margin-top:.25rem}.wind-doc pre{overflow-x:auto;border-radius:.6rem;background:color-mix(in oklab,var(--color-stone-900, #1c1917) 6%,transparent);padding:.8rem .9rem;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.875rem;line-height:1.55;white-space:pre-wrap}.wind-doc pre code{font:inherit;background:none;padding:0}.wind-doc a{color:var(--color-teal-800, #115e59);text-decoration:underline;text-underline-offset:2px}.wind-doc code{border-radius:.3rem;background:color-mix(in oklab,var(--color-stone-900, #1c1917) 8%,transparent);padding:.05em .3em;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.88em}.wind-doc img{display:block;max-width:100%;border-radius:.6rem}.wind-doc figure{margin:0}.wind-doc hr{border:0;border-top:1px solid var(--color-stone-300, #d6d3d1);margin:.25rem 0}.wind-doc [data-atomic].is-selected{outline:2px solid var(--color-teal-700, #0f766e);outline-offset:3px;border-radius:.4rem}.wind-doc[data-empty=true]>p[data-placeholder]:before{content:attr(data-placeholder);float:left;height:0;pointer-events:none;color:var(--color-stone-400, #a8a29e)}.wind-carets{position:absolute;inset:0;pointer-events:none;overflow:hidden}.wind-caret,.wind-remote{position:absolute;pointer-events:none}.wind-caret{width:2px;background:var(--peer);border-radius:1px}.wind-caret i{position:absolute;top:-1.15rem;left:-1px;border-radius:.3rem;background:var(--peer);color:#fff;padding:.05rem .3rem;font-family:var(--font-sans, ui-sans-serif, system-ui, sans-serif);font-size:.65rem;font-style:normal;line-height:1.3;letter-spacing:.01em;white-space:nowrap}.wind-remote{background:color-mix(in oklab,var(--peer) 32%,transparent);border-radius:.1rem}.wind-frame.is-readonly .wind-doc{caret-color:transparent}.dark .wind-doc{color:var(--color-stone-100, #f5f5f4);caret-color:var(--color-teal-300, #5eead4)}.dark .wind-doc h1,.dark .wind-doc h2,.dark .wind-doc h3{color:var(--color-stone-50, #fafaf9)}.dark .wind-doc blockquote{color:var(--color-stone-400, #a8a29e)}.dark .wind-doc a{color:var(--color-teal-300, #5eead4)}.dark .wind-doc hr{border-top-color:var(--color-stone-700, #44403c)}.dark .wind-doc pre,.dark .wind-doc code{background:color-mix(in oklab,white 8%,transparent)}.wind-editor.is-disabled{opacity:.7}.wind-shell{border:1px solid #e7e5e4;border-radius:.75rem;background:#fff;color:#1c1917;box-shadow:0 1px 2px #1c19170f}.wind-editor.is-invalid .wind-shell{border-color:#b91c1c}.wind-toolbar,.wind-pop,.wind-meta,.wind-error,.wind-source{border-color:#e7e5e4}.wind-toolbar{display:flex;gap:.125rem;overflow-x:auto;border-bottom:1px solid #e7e5e4;padding:.375rem}.wind-tool,.wind-primary,.wind-quiet,.wind-field,.wind-source-input{font:inherit}.wind-tool{display:inline-flex;height:2.25rem;flex:0 0 auto;align-items:center;justify-content:center;gap:.25rem;border:0;border-radius:.375rem;background:transparent;padding:0 .5rem;color:#57534e;font-size:.875rem;line-height:1;cursor:pointer}.wind-tool:hover{background:#f5f5f4}.wind-tool:disabled{opacity:.4;cursor:default}.wind-tool[aria-pressed=true]{background:#0f766e;color:#fff}.wind-tool-label{padding:0 .125rem;font-size:.75rem;font-weight:600;letter-spacing:.04em}.wind-pop,.wind-source{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;border-bottom:1px solid #e7e5e4;padding:.5rem .75rem}.wind-source{display:block;border-bottom:0;border-top:1px solid #e7e5e4}.wind-field,.wind-source-input{height:2.25rem;min-width:0;flex:1 1 12rem;border:1px solid #d6d3d1;border-radius:.375rem;background:#fff;padding:0 .5rem;color:inherit;font-size:.875rem;outline:none}.wind-field-short{flex:0 1 9rem;width:9rem}.wind-field:focus,.wind-source-input:focus{border-color:#0f766e}.wind-source-input{display:block;box-sizing:border-box;width:100%;height:10rem;resize:vertical;padding:.5rem;background:#fafaf9;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.75rem;line-height:1.5}.wind-primary,.wind-quiet{height:2.25rem;border:0;border-radius:.375rem;cursor:pointer;font-size:.875rem}.wind-primary{background:#0f766e;padding:0 .75rem;color:#fff;font-weight:500}.wind-quiet{background:transparent;padding:0 .5rem;color:#57534e}.wind-source .wind-primary{margin-top:.5rem;background:#1c1917}.wind-surface{position:relative;min-height:12rem}.wind-menu{position:fixed;z-index:30;max-height:16rem;width:14rem;overflow:auto;margin:0;border:1px solid #e7e5e4;border-radius:.5rem;background:#fff;padding:.25rem 0;list-style:none;box-shadow:0 10px 24px #1c19171f}.wind-option{display:flex;width:100%;align-items:baseline;justify-content:space-between;gap:.75rem;border:0;background:transparent;padding:.375rem .75rem;color:inherit;font:inherit;font-size:.875rem;text-align:left;cursor:pointer}.wind-option:hover,.wind-option.is-active{background:#f5f5f4}.wind-option.is-active{background:#0f766e;color:#fff}.wind-option-hint{font-size:.75rem;opacity:.7}.wind-meta,.wind-error{display:flex;align-items:center;justify-content:space-between;gap:.75rem;border-top:1px solid #e7e5e4;padding:.375rem .75rem;color:#78716c;font-size:.75rem}.wind-meta-hint{color:#a8a29e}.wind-error{color:#b91c1c}.wind-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.dark .wind-shell,.dark.wind-editor .wind-shell{border-color:#292524;background:#0c0a09;color:#f5f5f4}.dark .wind-editor.is-invalid .wind-shell,.dark.wind-editor.is-invalid .wind-shell{border-color:#f87171}.dark .wind-toolbar,.dark .wind-pop,.dark .wind-meta,.dark .wind-source,.dark.wind-editor .wind-toolbar,.dark.wind-editor .wind-pop,.dark.wind-editor .wind-meta,.dark.wind-editor .wind-source{border-color:#292524}.dark .wind-tool,.dark .wind-quiet,.dark.wind-editor .wind-tool,.dark.wind-editor .wind-quiet{color:#d6d3d1}.dark .wind-tool:hover,.dark.wind-editor .wind-tool:hover{background:#1c1917}.dark .wind-tool[aria-pressed=true],.dark.wind-editor .wind-tool[aria-pressed=true]{background:#0d9488;color:#fff}.dark .wind-field,.dark .wind-source-input,.dark.wind-editor .wind-field,.dark.wind-editor .wind-source-input{border-color:#44403c;background:#1c1917;color:#f5f5f4}.dark .wind-source .wind-primary,.dark.wind-editor .wind-source .wind-primary{background:#f5f5f4;color:#1c1917}.dark .wind-menu,.dark.wind-editor .wind-menu{border-color:#44403c;background:#1c1917}.dark .wind-option:hover,.dark.wind-editor .wind-option:hover{background:#292524}.dark .wind-option.is-active,.dark.wind-editor .wind-option.is-active{background:#0f766e;color:#fff}.dark .wind-meta,.dark.wind-editor .wind-meta{color:#a8a29e}.dark .wind-error,.dark.wind-editor .wind-error{border-color:#7f1d1d;color:#fca5a5}\n"],
2420
2500
  dependencies: [{
2421
2501
  kind: "component",
2422
2502
  type: WindIcon,
@@ -2440,24 +2520,32 @@ i0.ɵɵngDeclareClassMetadata({
2440
2520
  changeDetection: ChangeDetectionStrategy.OnPush,
2441
2521
  encapsulation: ViewEncapsulation.None,
2442
2522
  imports: [WindIcon],
2443
- host: { class: "wind-editor block min-w-0" },
2523
+ host: {
2524
+ class: "wind-editor",
2525
+ "(focusout)": "onFocusOut($event)",
2526
+ "[class.is-invalid]": "invalid()",
2527
+ "[class.is-disabled]": "disabled()",
2528
+ "[attr.aria-invalid]": "invalid() || null",
2529
+ "[attr.aria-required]": "required() || null",
2530
+ "[attr.aria-disabled]": "disabled() || null"
2531
+ },
2444
2532
  template: `
2445
- <div class="rounded-xl border border-stone-200 bg-white text-stone-900 shadow-sm dark:border-stone-800 dark:bg-stone-950 dark:text-stone-100">
2533
+ <div class="wind-shell">
2446
2534
  @if (showToolbar() && tools().length > 0) {
2447
- <div class="flex gap-0.5 overflow-x-auto border-b border-stone-200 px-1.5 py-1.5 dark:border-stone-800" role="toolbar" aria-label="Formatting">
2535
+ <div class="wind-toolbar" role="toolbar" aria-label="Formatting">
2448
2536
  @for (tool of tools(); track tool.id) {
2449
2537
  <button
2450
2538
  type="button"
2451
- class="inline-flex h-9 shrink-0 items-center justify-center gap-1 rounded-md px-2 text-sm text-stone-600 hover:bg-stone-100 disabled:opacity-40 aria-pressed:bg-teal-700 aria-pressed:text-white dark:text-stone-300 dark:hover:bg-stone-900 dark:aria-pressed:bg-teal-600"
2539
+ class="wind-tool"
2452
2540
  [attr.aria-label]="tool.label"
2453
2541
  [attr.title]="tool.label"
2454
2542
  [attr.aria-pressed]="pressed(tool.id)"
2455
- [disabled]="disabled(tool.id)"
2543
+ [disabled]="toolDisabled(tool.id)"
2456
2544
  (mousedown)="$event.preventDefault()"
2457
2545
  (click)="run(tool.id)"
2458
2546
  >
2459
2547
  @if (tool.id === 'paragraph' || tool.id === 'h1' || tool.id === 'h2') {
2460
- <span class="px-0.5 text-xs font-semibold tracking-wide">{{ tool.id === 'paragraph' ? 'P' : tool.id.toUpperCase() }}</span>
2548
+ <span class="wind-tool-label">{{ tool.id === 'paragraph' ? 'P' : tool.id.toUpperCase() }}</span>
2461
2549
  } @else {
2462
2550
  <wind-icon [name]="tool.icon" />
2463
2551
  }
@@ -2467,33 +2555,33 @@ i0.ɵɵngDeclareClassMetadata({
2467
2555
  }
2468
2556
 
2469
2557
  @if (linkOpen()) {
2470
- <form class="flex flex-wrap items-center gap-2 border-b border-stone-200 px-3 py-2 dark:border-stone-800" (submit)="applyLink($event)">
2471
- <label class="sr-only" for="wind-link">Link URL</label>
2558
+ <form class="wind-pop" (submit)="applyLink($event)">
2559
+ <label class="wind-sr" for="wind-link">Link URL</label>
2472
2560
  <input
2473
2561
  id="wind-link"
2474
- class="h-9 min-w-0 flex-1 rounded-md border border-stone-300 bg-white px-2 text-sm outline-none focus:border-teal-700 dark:border-stone-700 dark:bg-stone-900"
2562
+ class="wind-field"
2475
2563
  [value]="linkDraft()"
2476
2564
  placeholder="https://"
2477
2565
  (input)="onDraft($event, 'link')"
2478
2566
  />
2479
- <button type="submit" class="h-9 rounded-md bg-teal-700 px-3 text-sm font-medium text-white">Apply</button>
2480
- <button type="button" class="h-9 rounded-md px-2 text-sm text-stone-600 dark:text-stone-300" (click)="clearLink()">Remove</button>
2567
+ <button type="submit" class="wind-primary">Apply</button>
2568
+ <button type="button" class="wind-quiet" (click)="clearLink()">Remove</button>
2481
2569
  </form>
2482
2570
  }
2483
2571
 
2484
2572
  @if (imageOpen()) {
2485
- <form class="flex flex-wrap items-center gap-2 border-b border-stone-200 px-3 py-2 dark:border-stone-800" (submit)="applyImage($event)">
2486
- <input class="h-9 min-w-0 flex-1 rounded-md border border-stone-300 bg-white px-2 text-sm outline-none focus:border-teal-700 dark:border-stone-700 dark:bg-stone-900" [value]="imageSrc()" placeholder="Image URL" (input)="onDraft($event, 'src')" />
2487
- <input class="h-9 w-36 rounded-md border border-stone-300 bg-white px-2 text-sm outline-none focus:border-teal-700 dark:border-stone-700 dark:bg-stone-900" [value]="imageAlt()" placeholder="Alt text" (input)="onDraft($event, 'alt')" />
2488
- <button type="submit" class="h-9 rounded-md bg-teal-700 px-3 text-sm font-medium text-white">Insert</button>
2573
+ <form class="wind-pop" (submit)="applyImage($event)">
2574
+ <input class="wind-field" [value]="imageSrc()" placeholder="Image URL" (input)="onDraft($event, 'src')" />
2575
+ <input class="wind-field wind-field-short" [value]="imageAlt()" placeholder="Alt text" (input)="onDraft($event, 'alt')" />
2576
+ <button type="submit" class="wind-primary">Insert</button>
2489
2577
  </form>
2490
2578
  }
2491
2579
 
2492
- <div class="relative min-h-48" #surface></div>
2580
+ <div class="wind-surface" #surface></div>
2493
2581
 
2494
2582
  @if (slashItems().length > 0 && change()?.slashRect; as rect) {
2495
2583
  <ul
2496
- class="fixed z-30 max-h-64 w-56 overflow-auto rounded-lg border border-stone-200 bg-white py-1 shadow-lg dark:border-stone-700 dark:bg-stone-900"
2584
+ class="wind-menu"
2497
2585
  role="listbox"
2498
2586
  [style.top.px]="rect.top"
2499
2587
  [style.left.px]="rect.left"
@@ -2502,46 +2590,60 @@ i0.ɵɵngDeclareClassMetadata({
2502
2590
  <li>
2503
2591
  <button
2504
2592
  type="button"
2505
- class="flex w-full items-baseline justify-between gap-3 px-3 py-1.5 text-left text-sm hover:bg-stone-100 dark:hover:bg-stone-800"
2506
- [class.bg-teal-700]="index === slashIndex()"
2507
- [class.text-white]="index === slashIndex()"
2593
+ class="wind-option"
2594
+ [class.is-active]="index === slashIndex()"
2508
2595
  role="option"
2509
2596
  [attr.aria-selected]="index === slashIndex()"
2510
2597
  (mousedown)="$event.preventDefault()"
2511
2598
  (click)="pickSlash(item)"
2512
2599
  >
2513
2600
  <span>{{ item.label }}</span>
2514
- <span class="text-xs opacity-70">{{ item.hint }}</span>
2601
+ <span class="wind-option-hint">{{ item.hint }}</span>
2515
2602
  </button>
2516
2603
  </li>
2517
2604
  }
2518
2605
  </ul>
2519
2606
  }
2520
2607
 
2521
- <footer class="flex items-center justify-between gap-3 border-t border-stone-200 px-3 py-1.5 text-xs text-stone-500 dark:border-stone-800 dark:text-stone-400">
2608
+ <footer class="wind-meta">
2522
2609
  <span>{{ change()?.words ?? 0 }} words</span>
2523
- <span class="text-stone-400">/ for blocks</span>
2610
+ <span class="wind-meta-hint">/ for blocks</span>
2524
2611
  </footer>
2525
2612
 
2613
+ @if (invalid() && errorText()) {
2614
+ <p class="wind-error" role="alert">{{ errorText() }}</p>
2615
+ }
2616
+
2526
2617
  @if (sourceOpen()) {
2527
- <div class="border-t border-stone-200 p-3 dark:border-stone-800">
2618
+ <div class="wind-source">
2528
2619
  <textarea
2529
- class="h-40 w-full resize-y rounded-md border border-stone-300 bg-stone-50 p-2 font-mono text-xs outline-none focus:border-teal-700 dark:border-stone-700 dark:bg-stone-900"
2620
+ class="wind-source-input"
2530
2621
  [value]="sourceDraft()"
2531
2622
  spellcheck="false"
2532
2623
  aria-label="HTML source"
2533
2624
  (input)="onDraft($event, 'source')"
2534
2625
  ></textarea>
2535
- <button type="button" class="mt-2 h-9 rounded-md bg-stone-900 px-3 text-sm text-white dark:bg-stone-100 dark:text-stone-900" (click)="applySource()">Apply HTML</button>
2626
+ <button type="button" class="wind-primary" (click)="applySource()">Apply HTML</button>
2536
2627
  </div>
2537
2628
  }
2538
2629
  </div>
2539
2630
  `,
2540
- styles: [":host{display:block;min-width:0}.wind-frame{position:relative;min-width:0}.wind-doc{min-height:12rem;padding:1rem 1.15rem 1.5rem;outline:none;color:var(--color-stone-900, #1c1917);font-family:var(--font-serif, Georgia, \"Iowan Old Style\", \"Palatino Linotype\", serif);font-size:1.0625rem;line-height:1.65;caret-color:var(--color-teal-700, #0f766e);overflow-wrap:anywhere}.wind-doc>*+*{margin-top:.75rem}.wind-doc p,.wind-doc h1,.wind-doc h2,.wind-doc h3,.wind-doc blockquote,.wind-doc pre,.wind-doc li{margin:0}.wind-doc h1,.wind-doc h2,.wind-doc h3{font-family:var(--font-sans, ui-sans-serif, system-ui, sans-serif);line-height:1.2;letter-spacing:-.03em;color:var(--color-stone-950, #0c0a09)}.wind-doc h1{font-size:1.875rem;font-weight:600}.wind-doc h2{font-size:1.5rem;font-weight:600}.wind-doc h3{font-size:1.25rem;font-weight:600}.wind-doc blockquote{border-left:2px solid var(--color-teal-700, #0f766e);padding-left:.9rem;color:var(--color-stone-600, #57534e)}.wind-doc ul,.wind-doc ol{margin:0;padding-left:1.25rem}.wind-doc li+li{margin-top:.25rem}.wind-doc pre{overflow-x:auto;border-radius:.6rem;background:color-mix(in oklab,var(--color-stone-900, #1c1917) 6%,transparent);padding:.8rem .9rem;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.875rem;line-height:1.55;white-space:pre-wrap}.wind-doc pre code{font:inherit;background:none;padding:0}.wind-doc a{color:var(--color-teal-800, #115e59);text-decoration:underline;text-underline-offset:2px}.wind-doc code{border-radius:.3rem;background:color-mix(in oklab,var(--color-stone-900, #1c1917) 8%,transparent);padding:.05em .3em;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.88em}.wind-doc img{display:block;max-width:100%;border-radius:.6rem}.wind-doc figure{margin:0}.wind-doc hr{border:0;border-top:1px solid var(--color-stone-300, #d6d3d1);margin:.25rem 0}.wind-doc [data-atomic].is-selected{outline:2px solid var(--color-teal-700, #0f766e);outline-offset:3px;border-radius:.4rem}.wind-doc[data-empty=true]>p[data-placeholder]:before{content:attr(data-placeholder);float:left;height:0;pointer-events:none;color:var(--color-stone-400, #a8a29e)}.wind-carets{position:absolute;inset:0;pointer-events:none;overflow:hidden}.wind-caret,.wind-remote{position:absolute;pointer-events:none}.wind-caret{width:2px;background:var(--peer);border-radius:1px}.wind-caret i{position:absolute;top:-1.15rem;left:-1px;border-radius:.3rem;background:var(--peer);color:#fff;padding:.05rem .3rem;font-family:var(--font-sans, ui-sans-serif, system-ui, sans-serif);font-size:.65rem;font-style:normal;line-height:1.3;letter-spacing:.01em;white-space:nowrap}.wind-remote{background:color-mix(in oklab,var(--peer) 32%,transparent);border-radius:.1rem}.wind-frame.is-readonly .wind-doc{caret-color:transparent}.dark .wind-doc{color:var(--color-stone-100, #f5f5f4);caret-color:var(--color-teal-300, #5eead4)}.dark .wind-doc h1,.dark .wind-doc h2,.dark .wind-doc h3{color:var(--color-stone-50, #fafaf9)}.dark .wind-doc blockquote{color:var(--color-stone-400, #a8a29e)}.dark .wind-doc a{color:var(--color-teal-300, #5eead4)}.dark .wind-doc hr{border-top-color:var(--color-stone-700, #44403c)}.dark .wind-doc pre,.dark .wind-doc code{background:color-mix(in oklab,white 8%,transparent)}\n"]
2631
+ styles: ["wind-editor,.wind-editor{display:block;min-width:0;color:#1c1917;font-family:var(--font-sans, ui-sans-serif, system-ui, sans-serif)}.wind-frame{position:relative;min-width:0}.wind-doc{min-height:12rem;padding:1rem 1.15rem 1.5rem;outline:none;color:var(--color-stone-900, #1c1917);font-family:var(--font-serif, Georgia, \"Iowan Old Style\", \"Palatino Linotype\", serif);font-size:1.0625rem;line-height:1.65;caret-color:var(--color-teal-700, #0f766e);overflow-wrap:anywhere}.wind-doc>*+*{margin-top:.75rem}.wind-doc p,.wind-doc h1,.wind-doc h2,.wind-doc h3,.wind-doc blockquote,.wind-doc pre,.wind-doc li{margin:0}.wind-doc h1,.wind-doc h2,.wind-doc h3{font-family:var(--font-sans, ui-sans-serif, system-ui, sans-serif);line-height:1.2;letter-spacing:-.03em;color:var(--color-stone-950, #0c0a09)}.wind-doc h1{font-size:1.875rem;font-weight:600}.wind-doc h2{font-size:1.5rem;font-weight:600}.wind-doc h3{font-size:1.25rem;font-weight:600}.wind-doc blockquote{border-left:2px solid var(--color-teal-700, #0f766e);padding-left:.9rem;color:var(--color-stone-600, #57534e)}.wind-doc ul,.wind-doc ol{margin:0;padding-left:1.25rem}.wind-doc li+li{margin-top:.25rem}.wind-doc pre{overflow-x:auto;border-radius:.6rem;background:color-mix(in oklab,var(--color-stone-900, #1c1917) 6%,transparent);padding:.8rem .9rem;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.875rem;line-height:1.55;white-space:pre-wrap}.wind-doc pre code{font:inherit;background:none;padding:0}.wind-doc a{color:var(--color-teal-800, #115e59);text-decoration:underline;text-underline-offset:2px}.wind-doc code{border-radius:.3rem;background:color-mix(in oklab,var(--color-stone-900, #1c1917) 8%,transparent);padding:.05em .3em;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.88em}.wind-doc img{display:block;max-width:100%;border-radius:.6rem}.wind-doc figure{margin:0}.wind-doc hr{border:0;border-top:1px solid var(--color-stone-300, #d6d3d1);margin:.25rem 0}.wind-doc [data-atomic].is-selected{outline:2px solid var(--color-teal-700, #0f766e);outline-offset:3px;border-radius:.4rem}.wind-doc[data-empty=true]>p[data-placeholder]:before{content:attr(data-placeholder);float:left;height:0;pointer-events:none;color:var(--color-stone-400, #a8a29e)}.wind-carets{position:absolute;inset:0;pointer-events:none;overflow:hidden}.wind-caret,.wind-remote{position:absolute;pointer-events:none}.wind-caret{width:2px;background:var(--peer);border-radius:1px}.wind-caret i{position:absolute;top:-1.15rem;left:-1px;border-radius:.3rem;background:var(--peer);color:#fff;padding:.05rem .3rem;font-family:var(--font-sans, ui-sans-serif, system-ui, sans-serif);font-size:.65rem;font-style:normal;line-height:1.3;letter-spacing:.01em;white-space:nowrap}.wind-remote{background:color-mix(in oklab,var(--peer) 32%,transparent);border-radius:.1rem}.wind-frame.is-readonly .wind-doc{caret-color:transparent}.dark .wind-doc{color:var(--color-stone-100, #f5f5f4);caret-color:var(--color-teal-300, #5eead4)}.dark .wind-doc h1,.dark .wind-doc h2,.dark .wind-doc h3{color:var(--color-stone-50, #fafaf9)}.dark .wind-doc blockquote{color:var(--color-stone-400, #a8a29e)}.dark .wind-doc a{color:var(--color-teal-300, #5eead4)}.dark .wind-doc hr{border-top-color:var(--color-stone-700, #44403c)}.dark .wind-doc pre,.dark .wind-doc code{background:color-mix(in oklab,white 8%,transparent)}.wind-editor.is-disabled{opacity:.7}.wind-shell{border:1px solid #e7e5e4;border-radius:.75rem;background:#fff;color:#1c1917;box-shadow:0 1px 2px #1c19170f}.wind-editor.is-invalid .wind-shell{border-color:#b91c1c}.wind-toolbar,.wind-pop,.wind-meta,.wind-error,.wind-source{border-color:#e7e5e4}.wind-toolbar{display:flex;gap:.125rem;overflow-x:auto;border-bottom:1px solid #e7e5e4;padding:.375rem}.wind-tool,.wind-primary,.wind-quiet,.wind-field,.wind-source-input{font:inherit}.wind-tool{display:inline-flex;height:2.25rem;flex:0 0 auto;align-items:center;justify-content:center;gap:.25rem;border:0;border-radius:.375rem;background:transparent;padding:0 .5rem;color:#57534e;font-size:.875rem;line-height:1;cursor:pointer}.wind-tool:hover{background:#f5f5f4}.wind-tool:disabled{opacity:.4;cursor:default}.wind-tool[aria-pressed=true]{background:#0f766e;color:#fff}.wind-tool-label{padding:0 .125rem;font-size:.75rem;font-weight:600;letter-spacing:.04em}.wind-pop,.wind-source{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;border-bottom:1px solid #e7e5e4;padding:.5rem .75rem}.wind-source{display:block;border-bottom:0;border-top:1px solid #e7e5e4}.wind-field,.wind-source-input{height:2.25rem;min-width:0;flex:1 1 12rem;border:1px solid #d6d3d1;border-radius:.375rem;background:#fff;padding:0 .5rem;color:inherit;font-size:.875rem;outline:none}.wind-field-short{flex:0 1 9rem;width:9rem}.wind-field:focus,.wind-source-input:focus{border-color:#0f766e}.wind-source-input{display:block;box-sizing:border-box;width:100%;height:10rem;resize:vertical;padding:.5rem;background:#fafaf9;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.75rem;line-height:1.5}.wind-primary,.wind-quiet{height:2.25rem;border:0;border-radius:.375rem;cursor:pointer;font-size:.875rem}.wind-primary{background:#0f766e;padding:0 .75rem;color:#fff;font-weight:500}.wind-quiet{background:transparent;padding:0 .5rem;color:#57534e}.wind-source .wind-primary{margin-top:.5rem;background:#1c1917}.wind-surface{position:relative;min-height:12rem}.wind-menu{position:fixed;z-index:30;max-height:16rem;width:14rem;overflow:auto;margin:0;border:1px solid #e7e5e4;border-radius:.5rem;background:#fff;padding:.25rem 0;list-style:none;box-shadow:0 10px 24px #1c19171f}.wind-option{display:flex;width:100%;align-items:baseline;justify-content:space-between;gap:.75rem;border:0;background:transparent;padding:.375rem .75rem;color:inherit;font:inherit;font-size:.875rem;text-align:left;cursor:pointer}.wind-option:hover,.wind-option.is-active{background:#f5f5f4}.wind-option.is-active{background:#0f766e;color:#fff}.wind-option-hint{font-size:.75rem;opacity:.7}.wind-meta,.wind-error{display:flex;align-items:center;justify-content:space-between;gap:.75rem;border-top:1px solid #e7e5e4;padding:.375rem .75rem;color:#78716c;font-size:.75rem}.wind-meta-hint{color:#a8a29e}.wind-error{color:#b91c1c}.wind-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.dark .wind-shell,.dark.wind-editor .wind-shell{border-color:#292524;background:#0c0a09;color:#f5f5f4}.dark .wind-editor.is-invalid .wind-shell,.dark.wind-editor.is-invalid .wind-shell{border-color:#f87171}.dark .wind-toolbar,.dark .wind-pop,.dark .wind-meta,.dark .wind-source,.dark.wind-editor .wind-toolbar,.dark.wind-editor .wind-pop,.dark.wind-editor .wind-meta,.dark.wind-editor .wind-source{border-color:#292524}.dark .wind-tool,.dark .wind-quiet,.dark.wind-editor .wind-tool,.dark.wind-editor .wind-quiet{color:#d6d3d1}.dark .wind-tool:hover,.dark.wind-editor .wind-tool:hover{background:#1c1917}.dark .wind-tool[aria-pressed=true],.dark.wind-editor .wind-tool[aria-pressed=true]{background:#0d9488;color:#fff}.dark .wind-field,.dark .wind-source-input,.dark.wind-editor .wind-field,.dark.wind-editor .wind-source-input{border-color:#44403c;background:#1c1917;color:#f5f5f4}.dark .wind-source .wind-primary,.dark.wind-editor .wind-source .wind-primary{background:#f5f5f4;color:#1c1917}.dark .wind-menu,.dark.wind-editor .wind-menu{border-color:#44403c;background:#1c1917}.dark .wind-option:hover,.dark.wind-editor .wind-option:hover{background:#292524}.dark .wind-option.is-active,.dark.wind-editor .wind-option.is-active{background:#0f766e;color:#fff}.dark .wind-meta,.dark.wind-editor .wind-meta{color:#a8a29e}.dark .wind-error,.dark.wind-editor .wind-error{border-color:#7f1d1d;color:#fca5a5}\n"]
2541
2632
  }]
2542
2633
  }],
2543
2634
  ctorParameters: () => [],
2544
2635
  propDecorators: {
2636
+ value: [{
2637
+ type: i0.Input,
2638
+ args: [{
2639
+ isSignal: true,
2640
+ alias: "value",
2641
+ required: false
2642
+ }]
2643
+ }, {
2644
+ type: i0.Output,
2645
+ args: ["valueChange"]
2646
+ }],
2545
2647
  html: [{
2546
2648
  type: i0.Input,
2547
2649
  args: [{
@@ -2561,7 +2663,7 @@ i0.ɵɵngDeclareClassMetadata({
2561
2663
  required: false
2562
2664
  }]
2563
2665
  }],
2564
- readOnly: [{
2666
+ readonly: [{
2565
2667
  type: i0.Input,
2566
2668
  args: [{
2567
2669
  isSignal: true,
@@ -2569,6 +2671,50 @@ i0.ɵɵngDeclareClassMetadata({
2569
2671
  required: false
2570
2672
  }]
2571
2673
  }],
2674
+ disabled: [{
2675
+ type: i0.Input,
2676
+ args: [{
2677
+ isSignal: true,
2678
+ alias: "disabled",
2679
+ required: false
2680
+ }]
2681
+ }],
2682
+ invalid: [{
2683
+ type: i0.Input,
2684
+ args: [{
2685
+ isSignal: true,
2686
+ alias: "invalid",
2687
+ required: false
2688
+ }]
2689
+ }],
2690
+ required: [{
2691
+ type: i0.Input,
2692
+ args: [{
2693
+ isSignal: true,
2694
+ alias: "required",
2695
+ required: false
2696
+ }]
2697
+ }],
2698
+ touched: [{
2699
+ type: i0.Input,
2700
+ args: [{
2701
+ isSignal: true,
2702
+ alias: "touched",
2703
+ required: false
2704
+ }]
2705
+ }],
2706
+ errors: [{
2707
+ type: i0.Input,
2708
+ args: [{
2709
+ isSignal: true,
2710
+ alias: "errors",
2711
+ required: false
2712
+ }]
2713
+ }],
2714
+ touch: [{
2715
+ type: i0.Output,
2716
+ args: ["touch"]
2717
+ }],
2572
2718
  showToolbar: [{
2573
2719
  type: i0.Input,
2574
2720
  args: [{