@jarenjs/studio 0.72.0 → 0.72.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.
@@ -32,7 +32,11 @@ export declare function createStudioComponent(options?: {
32
32
  name: string;
33
33
  class: string;
34
34
  role: string;
35
- 'aria-orientation': string;
35
+ 'aria-orientation': {
36
+ $if: (string | {
37
+ $eq: string[];
38
+ })[];
39
+ };
36
40
  'aria-label': string;
37
41
  'aria-valuemin': string;
38
42
  'aria-valuemax': string;
@@ -41,6 +45,11 @@ export declare function createStudioComponent(options?: {
41
45
  props: {
42
46
  ratio: string;
43
47
  mode: string;
48
+ axis: {
49
+ $if: (string | {
50
+ $eq: string[];
51
+ })[];
52
+ };
44
53
  };
45
54
  })[] | (string | any[] | {
46
55
  class: string;
@@ -65,6 +74,12 @@ export declare function createStudioComponent(options?: {
65
74
  })[] | {
66
75
  class: string;
67
76
  $if?: undefined;
77
+ } | {
78
+ class?: undefined;
79
+ $if: (string | (string | {
80
+ class: string;
81
+ role: string;
82
+ })[])[];
68
83
  } | {
69
84
  class?: undefined;
70
85
  $if: ((string | (string | {
@@ -96,24 +111,6 @@ export declare function createStudioComponent(options?: {
96
111
  })[];
97
112
  $eq?: undefined;
98
113
  })[];
99
- })[] | (string | (string | {
100
- class: string;
101
- type: string;
102
- on: {
103
- click: string;
104
- };
105
- })[] | (string | any[] | {
106
- class: string;
107
- role: string;
108
- 'aria-label': string;
109
- })[] | (string | {
110
- $apply: string;
111
- }[] | (string | {
112
- class: string;
113
- })[] | {
114
- class: string;
115
- })[] | {
116
- class: string;
117
114
  })[] | (string | (string | {
118
115
  class: string;
119
116
  rows: number;
@@ -169,6 +166,33 @@ export declare function createStudioComponent(options?: {
169
166
  role: string;
170
167
  })[])[];
171
168
  class?: undefined;
169
+ })[] | (string | (string | {
170
+ class: string;
171
+ type: string;
172
+ 'aria-pressed': {
173
+ $if: string[];
174
+ };
175
+ on: {
176
+ click: string;
177
+ };
178
+ })[] | (string | {
179
+ class: string;
180
+ type: string;
181
+ on: {
182
+ click: string;
183
+ };
184
+ })[] | (string | any[] | {
185
+ class: string;
186
+ role: string;
187
+ 'aria-label': string;
188
+ })[] | (string | {
189
+ $apply: string;
190
+ }[] | (string | {
191
+ class: string;
192
+ })[] | {
193
+ class: string;
194
+ })[] | {
195
+ class: string;
172
196
  })[] | {
173
197
  class: string;
174
198
  'data-mode': string;
@@ -30,7 +30,11 @@ export declare const projectRules: ({
30
30
  name: string;
31
31
  class: string;
32
32
  role: string;
33
- 'aria-orientation': string;
33
+ 'aria-orientation': {
34
+ $if: (string | {
35
+ $eq: string[];
36
+ })[];
37
+ };
34
38
  'aria-label': string;
35
39
  'aria-valuemin': string;
36
40
  'aria-valuemax': string;
@@ -39,6 +43,11 @@ export declare const projectRules: ({
39
43
  props: {
40
44
  ratio: string;
41
45
  mode: string;
46
+ axis: {
47
+ $if: (string | {
48
+ $eq: string[];
49
+ })[];
50
+ };
42
51
  };
43
52
  })[] | (string | any[] | {
44
53
  class: string;
@@ -63,6 +72,12 @@ export declare const projectRules: ({
63
72
  })[] | {
64
73
  class: string;
65
74
  $if?: undefined;
75
+ } | {
76
+ class?: undefined;
77
+ $if: (string | (string | {
78
+ class: string;
79
+ role: string;
80
+ })[])[];
66
81
  } | {
67
82
  class?: undefined;
68
83
  $if: ((string | (string | {
@@ -94,24 +109,6 @@ export declare const projectRules: ({
94
109
  })[];
95
110
  $eq?: undefined;
96
111
  })[];
97
- })[] | (string | (string | {
98
- class: string;
99
- type: string;
100
- on: {
101
- click: string;
102
- };
103
- })[] | (string | any[] | {
104
- class: string;
105
- role: string;
106
- 'aria-label': string;
107
- })[] | (string | {
108
- $apply: string;
109
- }[] | (string | {
110
- class: string;
111
- })[] | {
112
- class: string;
113
- })[] | {
114
- class: string;
115
112
  })[] | (string | (string | {
116
113
  class: string;
117
114
  rows: number;
@@ -167,6 +164,33 @@ export declare const projectRules: ({
167
164
  role: string;
168
165
  })[])[];
169
166
  class?: undefined;
167
+ })[] | (string | (string | {
168
+ class: string;
169
+ type: string;
170
+ 'aria-pressed': {
171
+ $if: string[];
172
+ };
173
+ on: {
174
+ click: string;
175
+ };
176
+ })[] | (string | {
177
+ class: string;
178
+ type: string;
179
+ on: {
180
+ click: string;
181
+ };
182
+ })[] | (string | any[] | {
183
+ class: string;
184
+ role: string;
185
+ 'aria-label': string;
186
+ })[] | (string | {
187
+ $apply: string;
188
+ }[] | (string | {
189
+ class: string;
190
+ })[] | {
191
+ class: string;
192
+ })[] | {
193
+ class: string;
170
194
  })[] | {
171
195
  class: string;
172
196
  'data-mode': string;
@@ -72,6 +72,16 @@ than one name).
72
72
  autorun: boolean }`, defaulted to `{ classic, 0.5, true }`. It rides the
73
73
  share link and the eject, so its shape is fixed at v0.1.
74
74
 
75
+ The IDE honours `autorun`: when false, edits keep the last committed stage
76
+ until **Run** is pressed. The toolbar toggle changes the saved layout.
77
+ The splitter resizes the editor horizontally in `classic`/`right` and
78
+ vertically in `top`; pointer cancellation restores the previous ratio.
79
+
80
+ **Download** exports the complete `jaren-project` envelope, including every
81
+ file and the active file/layout, and works for projects without an app.
82
+ **App JSON** separately exports the designated app document and reports
83
+ when none exists. A runnable offline folder/ZIP is a future export format.
84
+
75
85
  ## `classifyChange` — reboot vs. hot-update
76
86
 
77
87
  `classifyChange(prev, next)` reports, **per artifact**, whether a change
@@ -109,8 +119,8 @@ Still open, and tracked with their constraints in
109
119
  validate but have no editor or runner, so they cannot be added from the
110
120
  IDE; fragment assembly (one artifact from several files) is unbuilt;
111
121
  the assistant authors files as free-form tool arguments rather than under
112
- constrained decoding; there is no whole-project export (`.zip` eject);
113
- `layout.autorun` is declared and never read; and the stage collects a
114
- nested app's failures without showing them. Syntax highlighting stays a
122
+ constrained decoding; and a runnable offline `.zip` eject is unbuilt.
123
+ The stage displays the nested app's latest boot/runtime failure and clears
124
+ it on restart. Syntax highlighting stays a
115
125
  non-goal — the editor is a plain `<textarea>` so the whole IDE remains a
116
126
  JSLT document with no imperative chrome.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jarenjs/studio",
3
3
  "private": false,
4
- "version": "0.72.0",
4
+ "version": "0.72.2",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
7
7
  "types": "./dist/types/index.d.ts",
@@ -59,12 +59,12 @@
59
59
  "prepack": "npm run build:types"
60
60
  },
61
61
  "dependencies": {
62
- "@jarenjs/core": "^0.72.0",
63
- "@jarenjs/validate": "^0.72.0",
64
- "@jarenjs/json": "^0.72.0",
65
- "@jarenjs/app": "^0.72.0",
66
- "@jarenjs/flow": "^0.72.0",
67
- "@jarenjs/db": "^0.72.0",
68
- "@jarenjs/contract": "^0.72.0"
62
+ "@jarenjs/core": "^0.72.2",
63
+ "@jarenjs/validate": "^0.72.2",
64
+ "@jarenjs/json": "^0.72.2",
65
+ "@jarenjs/app": "^0.72.2",
66
+ "@jarenjs/flow": "^0.72.2",
67
+ "@jarenjs/db": "^0.72.2",
68
+ "@jarenjs/contract": "^0.72.2"
69
69
  }
70
70
  }
@@ -75,6 +75,10 @@ const shell = {
75
75
  layoutButton('right', 'Swap', 'Stage beside the editor'),
76
76
  layoutButton('top', 'Stack', 'Editor over the stage'),
77
77
  ],
78
+ ['button', { class: 'btn small', type: 'button',
79
+ 'aria-pressed': { $if: ['$.layout.autorun', 'true', 'false'] },
80
+ on: { click: 'project/autorun' },
81
+ }, 'Autorun'],
78
82
  ['button', { class: 'btn small', type: 'button', on: { click: 'project/run' } }, 'Run'],
79
83
  ],
80
84
  // ——— file rail ———
@@ -132,15 +136,16 @@ const shell = {
132
136
  // ——— splitter (a pointer-capture widget; its host IS the grab bar) ———
133
137
  ['jaren-widget', {
134
138
  name: 'studio-splitter', class: 'js-split',
135
- role: 'separator', 'aria-orientation': 'vertical',
139
+ role: 'separator', 'aria-orientation': { $if: [{ $eq: ['$.layout.mode', 'top'] }, 'horizontal', 'vertical'] },
136
140
  'aria-label': 'Resize the editor and stage',
137
141
  'aria-valuemin': '10', 'aria-valuemax': '90', 'aria-valuenow': '$.ratioPct',
138
142
  tabindex: '0',
139
- props: { ratio: '$.layout.ratio', mode: '$.layout.mode' },
143
+ props: { ratio: '$.layout.ratio', mode: '$.layout.mode', axis: { $if: [{ $eq: ['$.layout.mode', 'top'] }, 'y', 'x'] } },
140
144
  }],
141
145
  // ——— stage ———
142
146
  ['div', { class: 'js-stage' },
143
147
  ['div', { class: 'js-stage-head' }, 'Stage'],
148
+ { $if: ['$.stageError', ['div', { class: 'js-stage-error js-stage-fail', role: 'status' }, '$.stageError'], ''] },
144
149
  { $if: [{ $eq: ['$.stage.kind', 'app'] },
145
150
  ['div', { class: 'js-stage-mount' }, ['jaren-widget', { name: 'studio-stage', props: '$.stage.mount' }]],
146
151
  { $if: [{ $eq: ['$.stage.kind', 'result'] },
@@ -143,6 +143,7 @@ export function projectViewModel(state, options = {}) {
143
143
  problems,
144
144
  problemCount: problems.length,
145
145
  stage: deriveStage(project, activeMeta, results, revision, committed),
146
+ stageError: slice.stageError ?? null,
146
147
  saveState: (slice.dirty === true || reconciled.dirty) ? 'Unsaved ●' : 'Saved',
147
148
  // the phone pane (Files · Editor · Stage). This is host chrome, not a
148
149
  // project member: `layout` travels with the saved document, which pane
package/styles/studio.css CHANGED
@@ -28,8 +28,8 @@
28
28
  .jstudio[data-mode="right"] { grid-template-areas: "penbar penbar penbar penbar" "rail stage split editor"; }
29
29
  .jstudio[data-mode="top"] {
30
30
  grid-template-columns: 11rem minmax(0, 1fr);
31
- grid-template-areas: "penbar penbar" "rail editor" "rail stage";
32
- grid-template-rows: auto minmax(0, 1fr) minmax(0, 1fr);
31
+ grid-template-areas: "penbar penbar" "rail editor" "rail split" "rail stage";
32
+ grid-template-rows: auto minmax(0, var(--js-ratio-first, 0.5fr)) auto minmax(0, var(--js-ratio-rest, 0.5fr));
33
33
  }
34
34
 
35
35
  .js-penbar {
@@ -167,8 +167,12 @@
167
167
  }
168
168
  .js-split:hover::before, .js-split:focus-visible::before { background: var(--accent, #2563eb); }
169
169
  .js-split:focus-visible { outline: none; }
170
- /* the stacked layout splits by rows; the horizontal handle is hidden there */
171
- .jstudio[data-mode="top"] .js-split { display: none; }
170
+ .jstudio[data-mode="top"] .js-split {
171
+ justify-self: stretch; inline-size: auto; block-size: 10px; cursor: row-resize;
172
+ }
173
+ .jstudio[data-mode="top"] .js-split::before {
174
+ inline-size: 100%; block-size: 4px; margin-block: auto;
175
+ }
172
176
 
173
177
  /* the phone pane switcher exists only below the breakpoint */
174
178
  .js-panebar { display: none; }
@@ -183,8 +187,10 @@
183
187
  @media (max-width: 1024px) {
184
188
  .jstudio, .jstudio[data-mode="right"], .jstudio[data-mode="top"] {
185
189
  grid-template-columns: minmax(0, 1fr);
186
- grid-template-areas: "penbar" "panes" "rail" "editor" "stage";
190
+ grid-template-areas: "penbar" "panes" "content";
191
+ grid-template-rows: auto auto minmax(0, 1fr);
187
192
  }
193
+ .js-rail, .js-editor, .js-stage { grid-area: content; }
188
194
  .js-panebar { display: flex; grid-area: panes; align-self: start; }
189
195
  .js-panebar .seg-btn { flex: 1; }
190
196
  .jstudio[data-pane="files"] .js-editor,