@nonoun/native-playground 0.2.0 → 0.2.1

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/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { NuiPlayground } from './nui-playground-element.ts';
1
+ export { NPlayground } from './playground-element.ts';
2
2
  export { createPlaygroundStore } from './playground-store.ts';
3
3
  export type { PlaygroundStore, ConsoleEntry } from './playground-store.ts';
4
4
  export { createEditor } from './editors.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAG5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAG3E,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG3E,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAG3E,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG3E,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,244 @@
1
+ @layer ui {
2
+ /* --- Host element --- */
3
+ :where(native-playground) {
4
+ /* Layout tokens */
5
+ --n-pg-min-height: 400px;
6
+ --n-pg-radius: var(--n-radius-lg, 0.75rem);
7
+ --n-pg-console-max-height: 200px;
8
+
9
+ /* Code-editor chrome tokens — NativeUI first, one-dark fallbacks */
10
+ --n-pg-chrome: var(--n-panel-neutral, #21252b);
11
+ --n-pg-editor-bg: var(--n-control-neutral, #282c34);
12
+ --n-pg-console-bg: var(--n-body-neutral, #1e2127);
13
+ --n-pg-border-color: var(--n-border-muted-neutral, #3e4451);
14
+ --n-pg-border: 1px solid var(--n-pg-border-color);
15
+ --n-pg-preview-bg: var(--n-body-neutral, #ffffff);
16
+
17
+ /* Text tokens — NativeUI first, one-dark fallbacks */
18
+ --n-pg-text: var(--n-ink-neutral, #abb2bf);
19
+ --n-pg-text-muted: var(--n-ink-muted-neutral, #7d8799);
20
+ --n-pg-text-strong: var(--n-ink-strong-neutral, #e5e7eb);
21
+
22
+ /* Accent tokens — NativeUI first, one-dark fallbacks */
23
+ --n-pg-accent: var(--n-ink-accent, #61afef);
24
+ --n-pg-run: var(--n-ink-success, #98c379);
25
+ --n-pg-run-hover: var(--n-ink-hover-success, #b5e890);
26
+ --n-pg-run-hover-bg: var(--n-control-success, #333d37);
27
+ --n-pg-warn: var(--n-ink-warning, #e5c07b);
28
+ --n-pg-error: var(--n-ink-danger, #e06c75);
29
+
30
+ display: grid;
31
+ grid-template-rows: auto 1fr;
32
+ min-height: var(--n-pg-min-height);
33
+ border-radius: var(--n-pg-radius);
34
+ border: var(--n-pg-border);
35
+ overflow: hidden;
36
+ contain: layout;
37
+ container-type: inline-size;
38
+ }
39
+
40
+ /* Toolbar button hover background (ghost variant forces transparent) */
41
+ :where(native-playground) > :where(n-card-header) :where(n-button):hover,
42
+ :where(native-playground) > :where(n-card-header) :where(n-button)[force-hover] {
43
+ background: var(--n-pg-editor-bg);
44
+ }
45
+
46
+ /* Run button — green accent override */
47
+ :where(native-playground) :where(.pg-btn-run) {
48
+ --n-color: var(--n-pg-run);
49
+ --n-color-hover: var(--n-pg-run-hover);
50
+ }
51
+
52
+ :where(native-playground) :where(.pg-btn-run):hover,
53
+ :where(native-playground) :where(.pg-btn-run)[force-hover] {
54
+ background: var(--n-pg-run-hover-bg);
55
+ }
56
+
57
+ /* --- Split layout (editor + handle + preview) --- */
58
+ :where(native-playground) > :where(.pg-split) {
59
+ display: flex;
60
+ min-height: 0;
61
+ overflow: hidden;
62
+ }
63
+
64
+ /* Vertical orientation */
65
+ :where(native-playground[orientation="vertical"]) > :where(.pg-split) {
66
+ flex-direction: column;
67
+ }
68
+
69
+ /* Auto orientation via container query */
70
+ @container (max-width: 600px) {
71
+ :where(native-playground[orientation="auto"]) > :where(.pg-split),
72
+ :where(native-playground:not([orientation])) > :where(.pg-split) {
73
+ flex-direction: column;
74
+ }
75
+ }
76
+
77
+ /* --- Resize handle (inside editor, positioned at edge) --- */
78
+ :where(native-playground) :where(.pg-resize-handle) {
79
+ position: absolute;
80
+ top: 0;
81
+ right: 0;
82
+ bottom: 0;
83
+ width: 6px;
84
+ cursor: col-resize;
85
+ background: transparent;
86
+ transition: background 150ms;
87
+ z-index: 1;
88
+ }
89
+
90
+ :where(native-playground) :where(.pg-resize-handle):hover,
91
+ :where(native-playground) :where(.pg-editor[resizing]) :where(.pg-resize-handle) {
92
+ background: var(--n-pg-accent);
93
+ }
94
+
95
+ /* Vertical handle */
96
+ :where(native-playground[orientation="vertical"]) :where(.pg-resize-handle) {
97
+ top: auto;
98
+ right: 0;
99
+ bottom: 0;
100
+ left: 0;
101
+ width: auto;
102
+ height: 6px;
103
+ cursor: row-resize;
104
+ }
105
+
106
+ @container (max-width: 600px) {
107
+ :where(native-playground[orientation="auto"]) :where(.pg-resize-handle),
108
+ :where(native-playground:not([orientation])) :where(.pg-resize-handle) {
109
+ top: auto;
110
+ right: 0;
111
+ bottom: 0;
112
+ left: 0;
113
+ width: auto;
114
+ height: 6px;
115
+ cursor: row-resize;
116
+ }
117
+ }
118
+
119
+ /* --- Editor region --- */
120
+ :where(native-playground) :where(.pg-editor) {
121
+ position: relative;
122
+ display: grid;
123
+ grid-template-rows: auto 1fr auto;
124
+ flex: 1 1 50%;
125
+ min-width: 200px;
126
+ min-height: 0;
127
+ overflow: hidden;
128
+ background: var(--n-pg-editor-bg);
129
+ }
130
+
131
+ /* When resized, respect the explicit width */
132
+ :where(native-playground) :where(.pg-editor[style*="width"]) {
133
+ flex: none;
134
+ }
135
+
136
+ /* Vertical: respect explicit height instead */
137
+ :where(native-playground[orientation="vertical"]) :where(.pg-editor) {
138
+ min-width: 0;
139
+ min-height: 100px;
140
+ }
141
+
142
+ :where(native-playground[orientation="vertical"]) :where(.pg-editor[style*="height"]) {
143
+ flex: none;
144
+ }
145
+
146
+ /* Card-header — dark chrome context for toolbar & tab bar */
147
+ :where(native-playground) :where(n-card-header) {
148
+ background: var(--n-pg-chrome);
149
+ border-bottom: var(--n-pg-border);
150
+ padding: 0;
151
+ --n-ink: var(--n-pg-text-muted);
152
+ --n-ink-hover: var(--n-pg-text);
153
+ --n-ink-strong: var(--n-pg-text-strong);
154
+ --n-border-muted: transparent;
155
+ --n-surface: var(--n-pg-accent);
156
+ --n-surface-ink: var(--n-pg-text-strong);
157
+ }
158
+
159
+ /* Code panels */
160
+ :where(native-playground) :where(.pg-code-panel) {
161
+ min-height: 0;
162
+ overflow: auto;
163
+ }
164
+
165
+ :where(native-playground) :where(.pg-code-panel[hidden]) {
166
+ display: none;
167
+ }
168
+
169
+ /* CodeMirror overrides */
170
+ :where(native-playground) :where(.cm-editor) {
171
+ height: 100%;
172
+ font-size: 0.8125rem;
173
+ }
174
+
175
+ :where(native-playground) :where(.cm-scroller) {
176
+ overflow: auto;
177
+ }
178
+
179
+ :where(native-playground) :where(.cm-gutters) {
180
+ border-right: none;
181
+ }
182
+
183
+ /* --- Console --- */
184
+ :where(native-playground) :where(.pg-console) {
185
+ max-height: var(--n-pg-console-max-height);
186
+ overflow-y: auto;
187
+ border-top: var(--n-pg-border);
188
+ background: var(--n-pg-console-bg);
189
+ font-family: ui-monospace, 'SF Mono', 'Cascadia Code', monospace;
190
+ font-size: 0.75rem;
191
+ padding: 0.375rem 0.5rem;
192
+ color: var(--n-pg-text);
193
+ }
194
+
195
+ :where(native-playground) :where(.pg-console[hidden]) {
196
+ display: none;
197
+ }
198
+
199
+ :where(native-playground) :where(.pg-console-line) {
200
+ padding: 0.125rem 0;
201
+ white-space: pre-wrap;
202
+ word-break: break-all;
203
+ }
204
+
205
+ :where(native-playground) :where(.pg-console-warn) {
206
+ color: var(--n-pg-warn);
207
+ }
208
+
209
+ :where(native-playground) :where(.pg-console-error) {
210
+ color: var(--n-pg-error);
211
+ }
212
+
213
+ /* --- Preview --- */
214
+ :where(native-playground) :where(.pg-preview) {
215
+ flex: 1 1 50%;
216
+ min-width: 200px;
217
+ min-height: 0;
218
+ overflow: hidden;
219
+ background: var(--n-pg-preview-bg);
220
+ border-left: var(--n-pg-border);
221
+ }
222
+
223
+ :where(native-playground[orientation="vertical"]) :where(.pg-preview) {
224
+ min-width: 0;
225
+ min-height: 100px;
226
+ border-left: none;
227
+ border-top: var(--n-pg-border);
228
+ }
229
+
230
+ @container (max-width: 600px) {
231
+ :where(native-playground[orientation="auto"]) :where(.pg-preview),
232
+ :where(native-playground:not([orientation])) :where(.pg-preview) {
233
+ border-left: none;
234
+ border-top: var(--n-pg-border);
235
+ }
236
+ }
237
+
238
+ :where(native-playground) :where(.pg-preview) > :where(iframe) {
239
+ display: block;
240
+ width: 100%;
241
+ height: 100%;
242
+ border: none;
243
+ }
244
+ }
@@ -0,0 +1,2 @@
1
+ import { i as e, n as t, r as n, t as r } from "./playground-element-DtAP76El.js";
2
+ export { r as NPlayground, t as buildSrcdoc, n as createEditor, e as createPlaygroundStore };
@@ -1,68 +1,68 @@
1
- import { CopyController as e, UIElement as t, signal as n } from "@nonoun/native-ui";
2
- import { EditorState as r } from "@codemirror/state";
3
- import { EditorView as i } from "@codemirror/view";
4
- import { nuiBaseExtensions as a, nuiSyntaxHighlighting as o, nuiTheme as s } from "@nonoun/nui-codemirror";
5
- import { html as c } from "@codemirror/lang-html";
6
- import { css as l } from "@codemirror/lang-css";
7
- import { javascript as u } from "@codemirror/lang-javascript";
8
- function d(e, t, r) {
1
+ import { CopyController as e, NativeElement as t, PresentController as n, ResizeController as r, signal as i } from "@nonoun/native-ui";
2
+ import { EditorState as a } from "@codemirror/state";
3
+ import { EditorView as o } from "@codemirror/view";
4
+ import { NBaseExtensions as s, NSyntaxHighlighting as c, NTheme as l } from "@nonoun/native-codemirror";
5
+ import { html as u } from "@codemirror/lang-html";
6
+ import { css as d } from "@codemirror/lang-css";
7
+ import { javascript as f } from "@codemirror/lang-javascript";
8
+ function p(e, t, n) {
9
9
  return {
10
- html: n(e),
11
- css: n(t),
12
- js: n(r),
10
+ html: i(e),
11
+ css: i(t),
12
+ js: i(n),
13
13
  initialHtml: e,
14
14
  initialCss: t,
15
- initialJs: r,
16
- activeTab: n("html"),
17
- consoleOpen: n(!1),
18
- fullscreen: n(!1),
19
- orientation: n("auto"),
20
- autoRun: n(!0),
21
- debounce: n(300),
22
- readonly: n(!1),
23
- consoleEntries: n([]),
24
- previewTheme: n("")
15
+ initialJs: n,
16
+ activeTab: i("html"),
17
+ consoleOpen: i(!1),
18
+ fullscreen: i(!1),
19
+ orientation: i("auto"),
20
+ autoRun: i(!0),
21
+ debounce: i(300),
22
+ readonly: i(!1),
23
+ consoleEntries: i([]),
24
+ previewTheme: i("")
25
25
  };
26
26
  }
27
- function f(e) {
27
+ function m(e) {
28
28
  switch (e) {
29
- case "html": return c();
30
- case "css": return l();
31
- case "js": return u();
29
+ case "html": return u();
30
+ case "css": return d();
31
+ case "js": return f();
32
32
  }
33
33
  }
34
- function p(e) {
35
- let { parent: t, initialCode: n, language: c, readonly: l = !1, onChange: u } = e, d = [
34
+ function h(e) {
35
+ let { parent: t, initialCode: n, language: r, readonly: i = !1, onChange: u } = e, d = [
36
+ l,
37
+ c,
36
38
  s,
37
- o,
38
- a,
39
- f(c),
40
- r.readOnly.of(l)
39
+ m(r),
40
+ a.readOnly.of(i)
41
41
  ];
42
- u && d.push(i.updateListener.of((e) => {
42
+ u && d.push(o.updateListener.of((e) => {
43
43
  e.docChanged && u(e.state.doc.toString());
44
44
  }));
45
- let p = new i({
46
- state: r.create({
45
+ let f = new o({
46
+ state: a.create({
47
47
  doc: n,
48
48
  extensions: d
49
49
  }),
50
50
  parent: t
51
51
  });
52
52
  return {
53
- view: p,
53
+ view: f,
54
54
  getCode() {
55
- return p.state.doc.toString();
55
+ return f.state.doc.toString();
56
56
  },
57
57
  setCode(e) {
58
- p.dispatch({ changes: {
58
+ f.dispatch({ changes: {
59
59
  from: 0,
60
- to: p.state.doc.length,
60
+ to: f.state.doc.length,
61
61
  insert: e
62
62
  } });
63
63
  },
64
64
  destroy() {
65
- p.destroy();
65
+ f.destroy();
66
66
  }
67
67
  };
68
68
  }
@@ -70,10 +70,10 @@ function p(e) {
70
70
  * Escape `<\/script>` sequences in user-provided JS to prevent
71
71
  * breaking out of the inline script tag.
72
72
  */
73
- function m(e) {
73
+ function g(e) {
74
74
  return e.replace(/<\/script>/gi, "<\\/script>");
75
75
  }
76
- function h(e) {
76
+ function _(e) {
77
77
  let { html: t, css: n, js: r, cssUrl: i, registerUrl: a, themeOverrides: o } = e;
78
78
  return `<!DOCTYPE html>
79
79
  <html>
@@ -115,19 +115,19 @@ function h(e) {
115
115
  window.parent.postMessage({ type: 'playground:ready' }, '*');
116
116
  })();
117
117
  <\/script>
118
- <script type="module">${m(r)}<\/script>
118
+ <script type="module">${g(r)}<\/script>
119
119
  </body>
120
120
  </html>`;
121
121
  }
122
- var g = [
122
+ var v = [
123
123
  "html",
124
124
  "css",
125
125
  "js"
126
- ], _ = {
126
+ ], y = {
127
127
  html: "HTML",
128
128
  css: "CSS",
129
129
  js: "JS"
130
- }, v = /* @__PURE__ */ new WeakMap(), y = class extends t {
130
+ }, b = class extends t {
131
131
  static observedAttributes = [
132
132
  "orientation",
133
133
  "auto-run",
@@ -144,16 +144,19 @@ var g = [
144
144
  #n = null;
145
145
  #r;
146
146
  #i;
147
- #a = [];
148
- #o = [];
147
+ #a = null;
148
+ #o = null;
149
149
  #s = null;
150
+ #c = [];
151
+ #l = null;
152
+ #u = null;
150
153
  /** Manually trigger a preview update. */
151
154
  run() {
152
- this.#p();
155
+ this.#g();
153
156
  }
154
157
  /** Reset all code to initial values. */
155
158
  reset() {
156
- this.#m();
159
+ this.#_();
157
160
  }
158
161
  /** Get the current code from all three editors. */
159
162
  getCode() {
@@ -165,8 +168,8 @@ var g = [
165
168
  }
166
169
  /** Programmatically set code in one or more editors. */
167
170
  setCode(e) {
168
- for (let t of g) e[t] !== void 0 && (this.#e[t].value = e[t], this.#t.get(t)?.setCode(e[t]));
169
- this.#e.autoRun.value && this.#f();
171
+ for (let t of v) e[t] !== void 0 && (this.#e[t].value = e[t], this.#t.get(t)?.setCode(e[t]));
172
+ this.#e.autoRun.value && this.#h();
170
173
  }
171
174
  attributeChangedCallback(e, t, n) {
172
175
  if (t !== n && this.#e) {
@@ -197,69 +200,83 @@ var g = [
197
200
  }
198
201
  }
199
202
  setup() {
200
- super.setup(), this.#e = d("", "", ""), this.#g(), this.#i = new e(this, { value: () => this.#e[this.#e.activeTab.value].value }), this.#c(), this.addEffect(() => {
201
- let e = this.#e.activeTab.value;
202
- for (let t = 0; t < g.length; t++) {
203
- let n = g[t] === e;
204
- this.#a[t].setAttribute("aria-selected", String(n)), this.#o[t].hidden = !n;
203
+ if (super.setup(), this.#e = p("", "", ""), this.#y(), this.#i = new e(this, { value: () => this.#e[this.#e.activeTab.value].value }), this.#d(), this.#o = new n(this), this.#u) {
204
+ let e = this.#e.orientation.value === "vertical";
205
+ this.#a = new r(this.#u, {
206
+ handleSelector: ".pg-resize-handle",
207
+ axis: e ? "vertical" : "horizontal",
208
+ min: e ? 100 : 200
209
+ });
210
+ }
211
+ this.addEffect(() => {
212
+ let e = this.#e.orientation.value;
213
+ if (this.#a) {
214
+ let t = e === "vertical";
215
+ this.#a.axis = t ? "vertical" : "horizontal", this.#a.min = t ? 100 : 200, this.#u && (this.#u.style.width = "", this.#u.style.height = "");
205
216
  }
217
+ }), this.addEffect(() => {
218
+ let e = this.#e.activeTab.value;
219
+ for (let t = 0; t < v.length; t++) this.#c[t].hidden = v[t] !== e;
220
+ this.#s && this.#s.setAttribute("value", e);
206
221
  }), this.addEffect(() => {
207
222
  let e = this.#e.consoleOpen.value;
208
- this.#s && (this.#s.hidden = !e);
223
+ this.#l && (this.#l.hidden = !e);
209
224
  }), this.addEffect(() => {
210
225
  let e = this.#e.consoleEntries.value;
211
- this.#h(e);
226
+ this.#v(e);
212
227
  }), this.addEffect(() => {
213
- this.#e.html.value, this.#e.css.value, this.#e.js.value, this.#e.autoRun.value && this.#f();
214
- }), window.addEventListener("message", this.#S), this.deferChildren(() => {
215
- this.#u(), this.#d(), this.#p();
228
+ this.#e.html.value, this.#e.css.value, this.#e.js.value, this.#e.autoRun.value && this.#h();
229
+ }), window.addEventListener("message", this.#E), this.deferChildren(() => {
230
+ this.#p(), this.#m(), this.#g();
216
231
  });
217
232
  }
218
233
  teardown() {
219
- window.removeEventListener("message", this.#S), clearTimeout(this.#r);
234
+ window.removeEventListener("message", this.#E), clearTimeout(this.#r);
220
235
  for (let e of this.#t.values()) e.destroy();
221
- this.#t.clear(), this.#i.destroy(), this.#n = null, this.#s = null, this.#a = [], this.#o = [], super.teardown();
236
+ this.#t.clear(), this.#i.destroy(), this.#a?.destroy(), this.#a = null, this.#o?.destroy(), this.#o = null, this.#n = null, this.#l = null, this.#u = null, this.#s = null, this.#c = [], super.teardown();
222
237
  }
223
- #c() {
224
- let e = document.createElement("div");
225
- e.className = "pg-toolbar";
226
- let t = this.#l("pg-btn pg-btn-run", "Run", "▶ Run");
227
- t.addEventListener("click", this.#_);
228
- let n = this.#l("pg-btn pg-btn-reset", "Reset", "↺ Reset");
229
- n.addEventListener("click", this.#v);
230
- let r = this.#l("pg-btn pg-btn-copy", "Copy", "Copy");
231
- r.addEventListener("click", this.#y);
232
- let i = document.createElement("span");
233
- i.className = "pg-spacer";
234
- let a = this.#l("pg-btn pg-btn-console", "Console", "Console");
235
- a.addEventListener("click", this.#b), e.append(t, n, r, i, a);
236
- let o = document.createElement("div");
237
- o.className = "pg-split";
238
+ #d() {
239
+ let e = document.createElement("n-card-header"), t = document.createElement("n-toolbar");
240
+ t.setAttribute("variant", "plain"), t.setAttribute("size", "md"), t.setAttribute("fill", "");
241
+ let n = this.#f("pg-btn-run", "Run", "▶ Run");
242
+ n.addEventListener("native:press", this.#b);
243
+ let r = this.#f("", "Reset", "↺ Reset");
244
+ r.addEventListener("native:press", this.#x);
245
+ let i = this.#f("", "Copy", "Copy");
246
+ i.addEventListener("native:press", this.#S);
247
+ let a = this.#f("", "Console", "Console");
248
+ a.addEventListener("native:press", this.#C);
249
+ let o = this.#f("", "Expand", "Expand");
250
+ o.addEventListener("native:press", this.#w), t.append(n, r, i, a, o), e.appendChild(t);
238
251
  let s = document.createElement("div");
239
- s.className = "pg-editor";
252
+ s.className = "pg-split";
240
253
  let c = document.createElement("div");
241
- c.className = "pg-tabs", c.setAttribute("role", "tablist");
242
- for (let e of g) {
243
- let t = document.createElement("button");
244
- t.className = "pg-tab", t.setAttribute("role", "tab"), t.setAttribute("aria-selected", e === this.#e.activeTab.value ? "true" : "false"), t.textContent = _[e], v.set(t, e), t.addEventListener("click", this.#x), c.appendChild(t), this.#a.push(t);
254
+ c.className = "pg-editor";
255
+ let l = document.createElement("n-card-header"), u = document.createElement("n-tabs");
256
+ u.setAttribute("value", this.#e.activeTab.value), u.setAttribute("size", "sm");
257
+ for (let e of v) {
258
+ let t = document.createElement("n-tab");
259
+ t.setAttribute("value", e), t.textContent = y[e], u.appendChild(t);
245
260
  }
246
- s.appendChild(c);
247
- for (let e = 0; e < g.length; e++) {
261
+ u.addEventListener("native:change", this.#T), this.#s = u, l.appendChild(u), c.appendChild(l);
262
+ for (let e = 0; e < v.length; e++) {
248
263
  let t = document.createElement("div");
249
- t.className = "pg-code-panel", t.setAttribute("role", "tabpanel"), t.hidden = g[e] !== this.#e.activeTab.value, s.appendChild(t), this.#o.push(t);
264
+ t.className = "pg-code-panel", t.setAttribute("role", "tabpanel"), t.hidden = v[e] !== this.#e.activeTab.value, c.appendChild(t), this.#c.push(t);
250
265
  }
251
- let l = document.createElement("div");
252
- l.className = "pg-console", l.hidden = !this.#e.consoleOpen.value, s.appendChild(l), this.#s = l, o.appendChild(s);
253
- let u = document.createElement("div");
254
- u.className = "pg-preview";
255
- let d = document.createElement("iframe");
256
- d.setAttribute("sandbox", "allow-scripts"), d.setAttribute("title", "Preview"), u.appendChild(d), this.#n = d, o.appendChild(u), this.append(e, o);
266
+ let d = document.createElement("div");
267
+ d.className = "pg-console", d.hidden = !this.#e.consoleOpen.value, c.appendChild(d), this.#l = d;
268
+ let f = document.createElement("div");
269
+ f.className = "pg-resize-handle", c.appendChild(f), s.appendChild(c), this.#u = c;
270
+ let p = document.createElement("div");
271
+ p.className = "pg-preview";
272
+ let m = document.createElement("iframe");
273
+ m.setAttribute("sandbox", "allow-scripts"), m.setAttribute("title", "Preview"), p.appendChild(m), this.#n = m, s.appendChild(p), this.append(e, s);
257
274
  }
258
- #l(e, t, n) {
259
- let r = document.createElement("button");
260
- return r.className = e, r.title = t, r.textContent = n, r;
275
+ #f(e, t, n) {
276
+ let r = document.createElement("n-button");
277
+ return r.className = e, r.title = t, r.setAttribute("variant", "ghost"), r.textContent = n, r;
261
278
  }
262
- #u() {
279
+ #p() {
263
280
  let e = this.querySelectorAll("script[type^=\"playground/\"]"), t = "", n = "", r = "";
264
281
  for (let i of e) {
265
282
  let e = (i.getAttribute("type") ?? "").replace("playground/", ""), a = (i.textContent ?? "").trim();
@@ -278,10 +295,10 @@ var g = [
278
295
  }
279
296
  this.#e.html.value = t, this.#e.css.value = n, this.#e.js.value = r, this.#e.initialHtml = t, this.#e.initialCss = n, this.#e.initialJs = r;
280
297
  }
281
- #d() {
298
+ #m() {
282
299
  let e = this.#e.readonly.value;
283
- for (let t = 0; t < g.length; t++) {
284
- let n = g[t], r = this.#o[t], i = this.#e[n], a = p({
300
+ for (let t = 0; t < v.length; t++) {
301
+ let n = v[t], r = this.#c[t], i = this.#e[n], a = h({
285
302
  parent: r,
286
303
  initialCode: i.value,
287
304
  language: n,
@@ -299,16 +316,16 @@ var g = [
299
316
  this.#t.set(n, a);
300
317
  }
301
318
  }
302
- #f() {
319
+ #h() {
303
320
  clearTimeout(this.#r), this.#r = setTimeout(() => {
304
- this.#p();
321
+ this.#g();
305
322
  }, this.#e.debounce.value);
306
323
  }
307
- #p() {
324
+ #g() {
308
325
  let e = this.#n;
309
326
  if (!e) return;
310
327
  let t = this.getAttribute("css-url") ?? "", n = this.getAttribute("register-url") ?? "", r = this.#e.html.value, i = this.#e.css.value, a = this.#e.js.value;
311
- this.#e.consoleEntries.value = [], e.srcdoc = h({
328
+ this.#e.consoleEntries.value = [], e.srcdoc = _({
312
329
  html: r,
313
330
  css: i,
314
331
  js: a,
@@ -324,7 +341,7 @@ var g = [
324
341
  }
325
342
  }));
326
343
  }
327
- #m() {
344
+ #_() {
328
345
  let { initialHtml: e, initialCss: t, initialJs: n } = this.#e;
329
346
  this.#e.html.value = e, this.#e.css.value = t, this.#e.js.value = n, this.#t.get("html")?.setCode(e), this.#t.get("css")?.setCode(t), this.#t.get("js")?.setCode(n), this.dispatchEvent(new CustomEvent("playground:reset", {
330
347
  bubbles: !0,
@@ -333,10 +350,10 @@ var g = [
333
350
  css: t,
334
351
  js: n
335
352
  }
336
- })), this.#p();
353
+ })), this.#g();
337
354
  }
338
- #h(e) {
339
- let t = this.#s;
355
+ #v(e) {
356
+ let t = this.#l;
340
357
  if (t) {
341
358
  t.textContent = "";
342
359
  for (let n of e) {
@@ -350,7 +367,7 @@ var g = [
350
367
  t.scrollTop = t.scrollHeight;
351
368
  }
352
369
  }
353
- #g() {
370
+ #y() {
354
371
  let e = this.getAttribute("orientation");
355
372
  (e === "horizontal" || e === "vertical" || e === "auto") && (this.#e.orientation.value = e), this.hasAttribute("auto-run") && (this.#e.autoRun.value = !0);
356
373
  let t = this.getAttribute("debounce");
@@ -360,13 +377,13 @@ var g = [
360
377
  let r = this.getAttribute("preview-theme");
361
378
  r && (this.#e.previewTheme.value = r);
362
379
  }
363
- #_ = () => {
364
- this.#p();
380
+ #b = () => {
381
+ this.#g();
365
382
  };
366
- #v = () => {
367
- this.#m();
383
+ #x = () => {
384
+ this.#_();
368
385
  };
369
- #y = async () => {
386
+ #S = async () => {
370
387
  let e = this.#e.activeTab.value, t = this.#e[e].value;
371
388
  await this.#i.copy(), this.dispatchEvent(new CustomEvent("playground:copy", {
372
389
  bubbles: !0,
@@ -376,14 +393,17 @@ var g = [
376
393
  }
377
394
  }));
378
395
  };
379
- #b = () => {
396
+ #C = () => {
380
397
  this.#e.consoleOpen.value = !this.#e.consoleOpen.value;
381
398
  };
382
- #x = (e) => {
383
- let t = e.currentTarget, n = v.get(t);
384
- n && (this.#e.activeTab.value = n);
399
+ #w = () => {
400
+ this.#o?.present();
401
+ };
402
+ #T = (e) => {
403
+ let t = e.detail;
404
+ (t?.value === "html" || t?.value === "css" || t?.value === "js") && (this.#e.activeTab.value = t.value);
385
405
  };
386
- #S = (e) => {
406
+ #E = (e) => {
387
407
  if (e.source !== this.#n?.contentWindow) return;
388
408
  let t = e.data;
389
409
  if (!(!t || typeof t != "object") && t.type === "playground:console") {
@@ -395,4 +415,4 @@ var g = [
395
415
  }
396
416
  };
397
417
  };
398
- export { d as i, h as n, p as r, y as t };
418
+ export { p as i, _ as n, h as r, b as t };
@@ -1,4 +1,4 @@
1
- import { UIElement } from '@nonoun/native-ui';
1
+ import { NativeElement } from '@nonoun/native-ui';
2
2
  import type { TabName } from './editors.ts';
3
3
  /**
4
4
  * Interactive code playground with live preview.
@@ -22,7 +22,7 @@ import type { TabName } from './editors.ts';
22
22
  * @fires playground:copy - When code is copied, detail: { tab, code }
23
23
  * @fires playground:reset - When code is reset, detail: { html, css, js }
24
24
  */
25
- export declare class NuiPlayground extends UIElement {
25
+ export declare class NPlayground extends NativeElement {
26
26
  #private;
27
27
  static observedAttributes: string[];
28
28
  /** Manually trigger a preview update. */
@@ -41,4 +41,4 @@ export declare class NuiPlayground extends UIElement {
41
41
  setup(): void;
42
42
  teardown(): void;
43
43
  }
44
- //# sourceMappingURL=nui-playground-element.d.ts.map
44
+ //# sourceMappingURL=playground-element.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playground-element.d.ts","sourceRoot":"","sources":["../src/playground-element.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAuD,MAAM,mBAAmB,CAAC;AAIvG,OAAO,KAAK,EAAkB,OAAO,EAAE,MAAM,cAAc,CAAC;AAM5D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,WAAY,SAAQ,aAAa;;IAC5C,MAAM,CAAC,kBAAkB,WAUvB;IAkBF,yCAAyC;IACzC,GAAG,IAAI,IAAI;IAIX,wCAAwC;IACxC,KAAK,IAAI,IAAI;IAIb,mDAAmD;IACnD,OAAO,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE;IAQpD,wDAAwD;IACxD,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI;IAYrD,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAqCpF,KAAK,IAAI,IAAI;IA6Fb,QAAQ,IAAI,IAAI;CAwXjB"}
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Register nui-playground
2
+ * Register native-playground
3
3
  *
4
- * Side-effect module that registers the <nui-playground> custom element.
4
+ * Side-effect module that registers the <native-playground> custom element.
5
5
  *
6
6
  * Usage:
7
7
  * import '@nonoun/native-playground/register';
package/dist/register.js CHANGED
@@ -1,11 +1,11 @@
1
- import { t as e } from "./nui-playground-element-DPT7rZeW.js";
1
+ import { t as e } from "./playground-element-DtAP76El.js";
2
2
  import { define as t } from "@nonoun/native-ui";
3
3
  /**
4
- * Register nui-playground
4
+ * Register native-playground
5
5
  *
6
- * Side-effect module that registers the <nui-playground> custom element.
6
+ * Side-effect module that registers the <native-playground> custom element.
7
7
  *
8
8
  * Usage:
9
- * import '@nonoun/nui-playground/register';
9
+ * import '@nonoun/native-playground/register';
10
10
  */
11
- t("nui-playground", e);
11
+ t("native-playground", e);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nonoun/native-playground",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Embeddable live code sandbox for @nonoun/native-ui",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -28,7 +28,7 @@
28
28
  "@nonoun/native-ui": ">=0.5.0"
29
29
  },
30
30
  "dependencies": {
31
- "@nonoun/native-codemirror": "^0.1.0",
31
+ "@nonoun/native-codemirror": "^0.2.0",
32
32
  "@codemirror/lang-css": "^6.3.1",
33
33
  "@codemirror/lang-html": "^6.4.9",
34
34
  "@codemirror/lang-javascript": "^6.2.3"
@@ -36,7 +36,7 @@
36
36
  "scripts": {
37
37
  "build": "npm run build:js && npm run build:css && npm run build:types",
38
38
  "build:js": "vite build",
39
- "build:css": "cp src/css/native-playground.css dist/native-playground.css",
39
+ "build:css": "cp src/css/playground.css dist/native-playground.css",
40
40
  "build:types": "tsc -p tsconfig.build.json"
41
41
  },
42
42
  "publishConfig": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"nui-playground-element.d.ts","sourceRoot":"","sources":["../src/nui-playground-element.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAkB,MAAM,mBAAmB,CAAC;AAI9D,OAAO,KAAK,EAAkB,OAAO,EAAE,MAAM,cAAc,CAAC;AAS5D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,aAAc,SAAQ,SAAS;;IAC1C,MAAM,CAAC,kBAAkB,WAUvB;IAeF,yCAAyC;IACzC,GAAG,IAAI,IAAI;IAIX,wCAAwC;IACxC,KAAK,IAAI,IAAI;IAIb,mDAAmD;IACnD,OAAO,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE;IAQpD,wDAAwD;IACxD,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI;IAYrD,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAqCpF,KAAK,IAAI,IAAI;IAkEb,QAAQ,IAAI,IAAI;CAoWjB"}
@@ -1,208 +0,0 @@
1
- @layer ui {
2
- /* --- Host element --- */
3
- :where(nui-playground) {
4
- --n-pg-min-height: 400px;
5
- --n-pg-radius: var(--ui-radius-lg, 0.75rem);
6
- --n-pg-border: 1px solid color-mix(in oklch, var(--n-border-muted-neutral, #e0e0e0), transparent 50%);
7
- --n-pg-chrome: #21252b;
8
- --n-pg-editor-bg: #282c34;
9
- --n-pg-preview-bg: var(--n-body-neutral, #ffffff);
10
- --n-pg-console-bg: #1e2127;
11
- --n-pg-console-max-height: 200px;
12
- --n-pg-toolbar-height: 2.5rem;
13
- --n-pg-text: #abb2bf;
14
- --n-pg-text-muted: #6b7280;
15
-
16
- display: grid;
17
- grid-template-rows: var(--n-pg-toolbar-height) 1fr;
18
- min-height: var(--n-pg-min-height);
19
- border-radius: var(--n-pg-radius);
20
- border: var(--n-pg-border);
21
- overflow: hidden;
22
- contain: layout;
23
- container-type: inline-size;
24
- }
25
-
26
- /* --- Toolbar --- */
27
- :where(nui-playground) > :where(.pg-toolbar) {
28
- display: flex;
29
- align-items: center;
30
- gap: 0.25rem;
31
- padding-inline: 0.5rem;
32
- border-bottom: var(--n-pg-border);
33
- background: var(--n-pg-chrome);
34
- }
35
-
36
- :where(nui-playground) > :where(.pg-toolbar) :where(.pg-spacer) {
37
- flex: 1;
38
- }
39
-
40
- /* Toolbar buttons */
41
- :where(nui-playground) :where(.pg-btn) {
42
- display: inline-flex;
43
- align-items: center;
44
- gap: 0.25rem;
45
- padding: 0.25rem 0.625rem;
46
- border: none;
47
- border-radius: 0.25rem;
48
- background: transparent;
49
- color: var(--n-pg-text-muted);
50
- font-family: inherit;
51
- font-size: 0.75rem;
52
- font-weight: 500;
53
- cursor: pointer;
54
- transition: color 150ms, background 150ms;
55
- white-space: nowrap;
56
- }
57
-
58
- :where(nui-playground) :where(.pg-btn):hover {
59
- color: var(--n-pg-text);
60
- background: var(--n-pg-editor-bg);
61
- }
62
-
63
- :where(nui-playground) :where(.pg-btn-run) {
64
- color: #98c379;
65
- }
66
-
67
- :where(nui-playground) :where(.pg-btn-run):hover {
68
- color: #b5e890;
69
- background: color-mix(in oklch, #98c379, transparent 85%);
70
- }
71
-
72
- /* --- Split layout (editor + preview) --- */
73
- :where(nui-playground) > :where(.pg-split) {
74
- display: grid;
75
- grid-template-columns: 1fr 1fr;
76
- min-height: 0;
77
- overflow: hidden;
78
- }
79
-
80
- /* Vertical orientation */
81
- :where(nui-playground[orientation="vertical"]) > :where(.pg-split) {
82
- grid-template-columns: 1fr;
83
- grid-template-rows: 1fr 1fr;
84
- }
85
-
86
- /* Auto orientation via container query */
87
- @container (max-width: 600px) {
88
- :where(nui-playground[orientation="auto"]) > :where(.pg-split),
89
- :where(nui-playground:not([orientation])) > :where(.pg-split) {
90
- grid-template-columns: 1fr;
91
- grid-template-rows: 1fr 1fr;
92
- }
93
- }
94
-
95
- /* --- Editor region --- */
96
- :where(nui-playground) :where(.pg-editor) {
97
- display: grid;
98
- grid-template-rows: auto 1fr auto;
99
- min-height: 0;
100
- overflow: hidden;
101
- background: var(--n-pg-editor-bg);
102
- }
103
-
104
- /* Tab bar */
105
- :where(nui-playground) :where(.pg-tabs) {
106
- display: flex;
107
- gap: 0;
108
- background: var(--n-pg-chrome);
109
- border-bottom: var(--n-pg-border);
110
- }
111
-
112
- :where(nui-playground) :where(.pg-tab) {
113
- padding: 0.375rem 0.75rem;
114
- font-family: inherit;
115
- font-size: 0.8125rem;
116
- font-weight: 500;
117
- cursor: pointer;
118
- border: none;
119
- background: transparent;
120
- color: var(--n-pg-text-muted);
121
- border-bottom: 2px solid transparent;
122
- transition: color 150ms, border-color 150ms;
123
- }
124
-
125
- :where(nui-playground) :where(.pg-tab):hover {
126
- color: var(--n-pg-text);
127
- }
128
-
129
- :where(nui-playground) :where(.pg-tab[aria-selected="true"]) {
130
- color: #e5e7eb;
131
- border-bottom-color: #61afef;
132
- }
133
-
134
- /* Code panels */
135
- :where(nui-playground) :where(.pg-code-panel) {
136
- min-height: 0;
137
- overflow: auto;
138
- }
139
-
140
- :where(nui-playground) :where(.pg-code-panel[hidden]) {
141
- display: none;
142
- }
143
-
144
- /* CodeMirror overrides */
145
- :where(nui-playground) :where(.cm-editor) {
146
- height: 100%;
147
- font-size: 0.8125rem;
148
- }
149
-
150
- :where(nui-playground) :where(.cm-scroller) {
151
- overflow: auto;
152
- }
153
-
154
- :where(nui-playground) :where(.cm-gutters) {
155
- border-right: none;
156
- }
157
-
158
- /* --- Console --- */
159
- :where(nui-playground) :where(.pg-console) {
160
- max-height: var(--n-pg-console-max-height);
161
- overflow-y: auto;
162
- border-top: var(--n-pg-border);
163
- background: var(--n-pg-console-bg);
164
- font-family: ui-monospace, 'SF Mono', 'Cascadia Code', monospace;
165
- font-size: 0.75rem;
166
- padding: 0.375rem 0.5rem;
167
- color: var(--n-pg-text);
168
- }
169
-
170
- :where(nui-playground) :where(.pg-console[hidden]) {
171
- display: none;
172
- }
173
-
174
- :where(nui-playground) :where(.pg-console-line) {
175
- padding: 0.125rem 0;
176
- white-space: pre-wrap;
177
- word-break: break-all;
178
- }
179
-
180
- :where(nui-playground) :where(.pg-console-warn) {
181
- color: #e5c07b;
182
- }
183
-
184
- :where(nui-playground) :where(.pg-console-error) {
185
- color: #e06c75;
186
- }
187
-
188
- /* --- Preview --- */
189
- :where(nui-playground) :where(.pg-preview) {
190
- min-height: 0;
191
- overflow: hidden;
192
- background: var(--n-pg-preview-bg);
193
- border-left: var(--n-pg-border);
194
- }
195
-
196
- :where(nui-playground[orientation="vertical"]) :where(.pg-preview),
197
- :where(nui-playground:not([orientation])) :where(.pg-preview) {
198
- border-left: none;
199
- border-top: var(--n-pg-border);
200
- }
201
-
202
- :where(nui-playground) :where(.pg-preview) > :where(iframe) {
203
- display: block;
204
- width: 100%;
205
- height: 100%;
206
- border: none;
207
- }
208
- }
@@ -1,2 +0,0 @@
1
- import { i as e, n as t, r as n, t as r } from "./nui-playground-element-DPT7rZeW.js";
2
- export { r as NuiPlayground, t as buildSrcdoc, n as createEditor, e as createPlaygroundStore };