@atscript/ui 0.1.85 → 0.1.86

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.cjs CHANGED
@@ -14,6 +14,7 @@ const UI_FORM_ORDER = "ui.form.order";
14
14
  const UI_FORM_TYPE = "ui.form.type";
15
15
  const UI_FORM_COMPONENT = "ui.form.component";
16
16
  const UI_FORM_HIDDEN = "ui.form.hidden";
17
+ const UI_FORM_PUSH_DOWN = "ui.form.pushDown";
17
18
  const UI_FORM_ATTR = "ui.form.attr";
18
19
  const UI_FORM_GRID_COL_SPAN = "ui.form.grid.colSpan";
19
20
  const UI_FORM_GRID_ROW_SPAN = "ui.form.grid.rowSpan";
@@ -290,10 +291,13 @@ const UI_TAGS = new Set([
290
291
  function createFormDef(type, opts) {
291
292
  if (type.type.kind !== "object") {
292
293
  const rootField = createFieldDef("", type);
294
+ const fields = [rootField];
293
295
  return {
294
296
  type,
295
297
  rootField,
296
- fields: [rootField],
298
+ fields,
299
+ mainFields: fields,
300
+ pushDownFields: [],
297
301
  flatMap: /* @__PURE__ */ new Map()
298
302
  };
299
303
  }
@@ -326,12 +330,21 @@ function createFormDef(type, opts) {
326
330
  type: "object",
327
331
  phantom: false,
328
332
  name: "",
329
- allStatic: false
333
+ allStatic: false,
334
+ pushDown: false
330
335
  };
336
+ let mainFields = fields;
337
+ const pushDownFields = [];
338
+ if (fields.some((f) => f.pushDown)) {
339
+ mainFields = [];
340
+ for (const f of fields) (f.pushDown ? pushDownFields : mainFields).push(f);
341
+ }
331
342
  const def = {
332
343
  type,
333
344
  rootField,
334
345
  fields,
346
+ mainFields,
347
+ pushDownFields,
335
348
  flatMap
336
349
  };
337
350
  rootField.objectDef = def;
@@ -343,12 +356,14 @@ function createFieldDef(path, prop) {
343
356
  const name = path.slice(path.lastIndexOf(".") + 1);
344
357
  const allStatic = !hasComputedAnnotations(prop);
345
358
  const uiType = getFieldMeta(prop, "ui.form.type") ?? getFieldMeta(prop, "ui.type");
359
+ const pushDown = getFieldMeta(prop, UI_FORM_PUSH_DOWN) !== void 0;
346
360
  const base = {
347
361
  path,
348
362
  prop,
349
363
  phantom: false,
350
364
  name,
351
- allStatic
365
+ allStatic,
366
+ pushDown
352
367
  };
353
368
  const customType = uiType;
354
369
  if (kind === "array") {
@@ -385,7 +400,8 @@ function createFieldDef(path, prop) {
385
400
  ...v.itemField,
386
401
  path,
387
402
  name,
388
- allStatic
403
+ allStatic,
404
+ pushDown
389
405
  };
390
406
  if (v?.def) return {
391
407
  ...base,
package/dist/index.d.cts CHANGED
@@ -140,6 +140,13 @@ interface FormFieldDef {
140
140
  name: string;
141
141
  /** True when no `ui.fn.*` metadata keys exist. Vue perf flag. */
142
142
  allStatic: boolean;
143
+ /**
144
+ * `@ui.form.pushDown` — render this field below the submit button in its
145
+ * own grid, instead of in the main field grid above submit. Set on
146
+ * top-level form fields (typically secondary `ui.action` links). The field
147
+ * stays in `fields[]` for validation/data; only its render slot moves.
148
+ */
149
+ pushDown: boolean;
143
150
  }
144
151
  /**
145
152
  * Complete form definition — produced by createFormDef().
@@ -150,6 +157,15 @@ interface FormDef {
150
157
  /** Root field representing the entire form. For interface types this is `type='object'`; for single-type forms it is a leaf field. */
151
158
  rootField: FormFieldDef;
152
159
  fields: FormFieldDef[];
160
+ /**
161
+ * Render partition of `fields` by `@ui.form.pushDown`, precomputed once so
162
+ * the renderer never re-scans per frame. `mainFields` (above submit) plus
163
+ * `pushDownFields` (below submit) cover `fields` exactly once. In the common
164
+ * case nothing is pushed down: `mainFields === fields` (same ref) and
165
+ * `pushDownFields` is empty.
166
+ */
167
+ mainFields: FormFieldDef[];
168
+ pushDownFields: FormFieldDef[];
153
169
  flatMap: Map<string, TAtscriptAnnotatedType>;
154
170
  }
155
171
  /** One branch of a union type — used by union fields and union array items. */
package/dist/index.d.mts CHANGED
@@ -140,6 +140,13 @@ interface FormFieldDef {
140
140
  name: string;
141
141
  /** True when no `ui.fn.*` metadata keys exist. Vue perf flag. */
142
142
  allStatic: boolean;
143
+ /**
144
+ * `@ui.form.pushDown` — render this field below the submit button in its
145
+ * own grid, instead of in the main field grid above submit. Set on
146
+ * top-level form fields (typically secondary `ui.action` links). The field
147
+ * stays in `fields[]` for validation/data; only its render slot moves.
148
+ */
149
+ pushDown: boolean;
143
150
  }
144
151
  /**
145
152
  * Complete form definition — produced by createFormDef().
@@ -150,6 +157,15 @@ interface FormDef {
150
157
  /** Root field representing the entire form. For interface types this is `type='object'`; for single-type forms it is a leaf field. */
151
158
  rootField: FormFieldDef;
152
159
  fields: FormFieldDef[];
160
+ /**
161
+ * Render partition of `fields` by `@ui.form.pushDown`, precomputed once so
162
+ * the renderer never re-scans per frame. `mainFields` (above submit) plus
163
+ * `pushDownFields` (below submit) cover `fields` exactly once. In the common
164
+ * case nothing is pushed down: `mainFields === fields` (same ref) and
165
+ * `pushDownFields` is empty.
166
+ */
167
+ mainFields: FormFieldDef[];
168
+ pushDownFields: FormFieldDef[];
153
169
  flatMap: Map<string, TAtscriptAnnotatedType>;
154
170
  }
155
171
  /** One branch of a union type — used by union fields and union array items. */
package/dist/index.mjs CHANGED
@@ -13,6 +13,7 @@ const UI_FORM_ORDER = "ui.form.order";
13
13
  const UI_FORM_TYPE = "ui.form.type";
14
14
  const UI_FORM_COMPONENT = "ui.form.component";
15
15
  const UI_FORM_HIDDEN = "ui.form.hidden";
16
+ const UI_FORM_PUSH_DOWN = "ui.form.pushDown";
16
17
  const UI_FORM_ATTR = "ui.form.attr";
17
18
  const UI_FORM_GRID_COL_SPAN = "ui.form.grid.colSpan";
18
19
  const UI_FORM_GRID_ROW_SPAN = "ui.form.grid.rowSpan";
@@ -289,10 +290,13 @@ const UI_TAGS = new Set([
289
290
  function createFormDef(type, opts) {
290
291
  if (type.type.kind !== "object") {
291
292
  const rootField = createFieldDef("", type);
293
+ const fields = [rootField];
292
294
  return {
293
295
  type,
294
296
  rootField,
295
- fields: [rootField],
297
+ fields,
298
+ mainFields: fields,
299
+ pushDownFields: [],
296
300
  flatMap: /* @__PURE__ */ new Map()
297
301
  };
298
302
  }
@@ -325,12 +329,21 @@ function createFormDef(type, opts) {
325
329
  type: "object",
326
330
  phantom: false,
327
331
  name: "",
328
- allStatic: false
332
+ allStatic: false,
333
+ pushDown: false
329
334
  };
335
+ let mainFields = fields;
336
+ const pushDownFields = [];
337
+ if (fields.some((f) => f.pushDown)) {
338
+ mainFields = [];
339
+ for (const f of fields) (f.pushDown ? pushDownFields : mainFields).push(f);
340
+ }
330
341
  const def = {
331
342
  type,
332
343
  rootField,
333
344
  fields,
345
+ mainFields,
346
+ pushDownFields,
334
347
  flatMap
335
348
  };
336
349
  rootField.objectDef = def;
@@ -342,12 +355,14 @@ function createFieldDef(path, prop) {
342
355
  const name = path.slice(path.lastIndexOf(".") + 1);
343
356
  const allStatic = !hasComputedAnnotations(prop);
344
357
  const uiType = getFieldMeta(prop, "ui.form.type") ?? getFieldMeta(prop, "ui.type");
358
+ const pushDown = getFieldMeta(prop, UI_FORM_PUSH_DOWN) !== void 0;
345
359
  const base = {
346
360
  path,
347
361
  prop,
348
362
  phantom: false,
349
363
  name,
350
- allStatic
364
+ allStatic,
365
+ pushDown
351
366
  };
352
367
  const customType = uiType;
353
368
  if (kind === "array") {
@@ -384,7 +399,8 @@ function createFieldDef(path, prop) {
384
399
  ...v.itemField,
385
400
  path,
386
401
  name,
387
- allStatic
402
+ allStatic,
403
+ pushDown
388
404
  };
389
405
  if (v?.def) return {
390
406
  ...base,
package/dist/plugin.cjs CHANGED
@@ -244,6 +244,10 @@ const uiAnnotations = { ui: {
244
244
  description: "Singular label, e.g. \"phone number\" for a `phones` field."
245
245
  }
246
246
  }) },
247
+ pushDown: new _atscript_core.AnnotationSpec({
248
+ description: "Render this field below the form's submit button instead of above it. Pushed-down fields collect into their own grid (same 12-column layout, `@ui.form.order`/`@ui.form.grid.*` honoured) that sits under the submit action. Typical use: a secondary `ui.action` link such as \"Already have an account? Sign in\" beneath a Sign-up button.\n\n**Example:**\n```atscript\n@ui.form.pushDown\n@ui.form.attr 'text', 'Already have an account?'\n@ui.form.attr 'align', 'center'\n@ui.form.action 'signin', 'Sign in'\nsigninAction: ui.action\n```\n",
249
+ nodeType: ["prop", "type"]
250
+ }),
247
251
  action: new _atscript_core.AnnotationSpec({
248
252
  description: "Form action button for this field.",
249
253
  nodeType: ["prop", "type"],
package/dist/plugin.mjs CHANGED
@@ -244,6 +244,10 @@ const uiAnnotations = { ui: {
244
244
  description: "Singular label, e.g. \"phone number\" for a `phones` field."
245
245
  }
246
246
  }) },
247
+ pushDown: new AnnotationSpec({
248
+ description: "Render this field below the form's submit button instead of above it. Pushed-down fields collect into their own grid (same 12-column layout, `@ui.form.order`/`@ui.form.grid.*` honoured) that sits under the submit action. Typical use: a secondary `ui.action` link such as \"Already have an account? Sign in\" beneath a Sign-up button.\n\n**Example:**\n```atscript\n@ui.form.pushDown\n@ui.form.attr 'text', 'Already have an account?'\n@ui.form.attr 'align', 'center'\n@ui.form.action 'signin', 'Sign in'\nsigninAction: ui.action\n```\n",
249
+ nodeType: ["prop", "type"]
250
+ }),
247
251
  action: new AnnotationSpec({
248
252
  description: "Form action button for this field.",
249
253
  nodeType: ["prop", "type"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/ui",
3
- "version": "0.1.85",
3
+ "version": "0.1.86",
4
4
  "description": "Framework-agnostic runtime for form and table definitions from atscript annotated types",
5
5
  "keywords": [
6
6
  "annotations",