@svgrid/enterprise 2.6.0 → 2.6.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.
- package/dist/ExpressionEditorHarness.svelte +47 -0
- package/dist/ExpressionEditorHarness.svelte.d.ts +15 -0
- package/dist/SvAdvancedFilter.svelte +208 -0
- package/dist/SvAdvancedFilter.svelte.d.ts +37 -0
- package/dist/SvExpressionEditor.svelte +255 -124
- package/dist/SvGridEditPanel.svelte +1157 -1012
- package/dist/SvGridEditPanel.svelte.d.ts +2 -0
- package/dist/advanced-filter/expr-columns-from-grid.d.ts +30 -0
- package/dist/advanced-filter/expr-columns-from-grid.js +44 -0
- package/dist/advanced-filter-enable.d.ts +5 -0
- package/dist/advanced-filter-enable.js +35 -0
- package/dist/cdn/svgrid-enterprise.svelte-external.js +7663 -6482
- package/dist/designer/assets/GridMenus-Bjr19Tz_.js +7 -0
- package/dist/designer/assets/{SvListBox-BVzVfCG3.js → SvListBox-BB8rt4aP.js} +1 -1
- package/dist/designer/assets/index-BfzoL904.css +1 -0
- package/dist/designer/assets/{index-BF0UH638.js → index-xjfKckuH.js} +139 -139
- package/dist/designer/assets/{js-scroller.svelte-tHanKJx0.js → js-scroller.svelte-CGkUUXwV.js} +2 -2
- package/dist/designer/assets/src-BT3LjWJL.css +1 -0
- package/dist/designer/assets/src-DDhAK0WP.js +2893 -0
- package/dist/designer/index.html +6 -6
- package/dist/expressions/builder-tree.d.ts +62 -0
- package/dist/expressions/builder-tree.js +133 -0
- package/dist/expressions/compile.d.ts +14 -0
- package/dist/expressions/compile.js +286 -0
- package/dist/expressions/expression-columns.d.ts +1 -11
- package/dist/expressions/expression-columns.js +40 -11
- package/dist/index.d.ts +7 -3
- package/dist/index.js +7 -3
- package/dist/install.js +2 -0
- package/dist/node/studio.js +743 -25
- package/dist/schema.d.ts +39 -0
- package/dist/schema.js +9 -0
- package/dist/sources/rest.js +25 -0
- package/dist/sources/supabase.js +49 -3
- package/dist/studio/emit-project.js +85 -11
- package/dist/studio/index.d.ts +2 -2
- package/dist/studio/index.js +5 -2
- package/dist/studio/project.d.ts +124 -3
- package/dist/studio/project.js +393 -4
- package/dist/studio/ui-components.generated.js +213 -0
- package/dist/sveltekit/in-memory.js +96 -3
- package/dist/sveltekit/query-plan.d.ts +32 -1
- package/dist/sveltekit/query-plan.js +88 -1
- package/dist/sveltekit/sql.d.ts +20 -0
- package/dist/sveltekit/sql.js +26 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/dist/designer/assets/GridMenus-CW-rnHS9.js +0 -7
- package/dist/designer/assets/index-oYok52zd.css +0 -1
- package/dist/designer/assets/src-BPJruwB9.js +0 -2873
- package/dist/designer/assets/src-D-O2F805.css +0 -1
package/dist/node/studio.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "@svgrid/grid/filtering";
|
|
1
|
+
import { isRangeOperator, isSetOperator, isValuelessOperator } from "@svgrid/grid/filtering";
|
|
2
2
|
import { defaultThemePreset, getThemePreset, resolveThemeTokens as resolveThemeTokens$1, themePresets } from "@svgrid/grid/themes";
|
|
3
3
|
//#region src/schema.ts
|
|
4
4
|
/** `first_name` / `firstName` / `first-name` -> `First Name`. */
|
|
@@ -66,6 +66,15 @@ function hiddenFor(field, surface) {
|
|
|
66
66
|
return false;
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
|
+
* Whether a field is hidden from one surface. Public because the `hidden`
|
|
70
|
+
* union (`true` means both surfaces, an object names them) is exactly the kind
|
|
71
|
+
* of logic that drifts when every caller re-derives it - the form builder's
|
|
72
|
+
* "Hidden from this form" tray is one such caller.
|
|
73
|
+
*/
|
|
74
|
+
function isFieldHidden(field, surface) {
|
|
75
|
+
return hiddenFor(field, surface);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
69
78
|
* Derive grid columns from a schema. Read-only fields become non-editable
|
|
70
79
|
* columns; `enum` carries its options through as `editorOptions`. The
|
|
71
80
|
* per-field `column` escape hatch is merged last, so any explicit grid prop
|
|
@@ -1923,6 +1932,21 @@ function scaffoldApp(schemas, options = {}) {
|
|
|
1923
1932
|
}
|
|
1924
1933
|
//#endregion
|
|
1925
1934
|
//#region src/expressions/expression-columns.ts
|
|
1935
|
+
/**
|
|
1936
|
+
* Column metadata for the expression layer - the small, self-contained operator
|
|
1937
|
+
* catalogue the editor draws from, plus name <-> id resolution for the
|
|
1938
|
+
* `[Bracketed Name]` reference syntax.
|
|
1939
|
+
*
|
|
1940
|
+
* The operator set mirrors the grid's own filter row (text / number / date),
|
|
1941
|
+
* so an expression's operators line up with what a user already knows from the
|
|
1942
|
+
* column menu.
|
|
1943
|
+
*
|
|
1944
|
+
* Identity and input-shape semantics come from the grid's shared catalogue, so
|
|
1945
|
+
* the two surfaces cannot disagree about which operators exist or which need a
|
|
1946
|
+
* chip input / no input / a second value. Labels and ordering stay local on
|
|
1947
|
+
* purpose: the editor leads with `Equals` where the filter menu leads with
|
|
1948
|
+
* `Contains`, and each is right for its context.
|
|
1949
|
+
*/
|
|
1926
1950
|
var TEXT = ["text"];
|
|
1927
1951
|
var NUM = ["number"];
|
|
1928
1952
|
var DATES = ["date", "datetime"];
|
|
@@ -1983,34 +2007,34 @@ var OPERATORS = [
|
|
|
1983
2007
|
{
|
|
1984
2008
|
value: "between",
|
|
1985
2009
|
label: "Between",
|
|
1986
|
-
types: [...NUM, ...DATES]
|
|
1987
|
-
range: true
|
|
2010
|
+
types: [...NUM, ...DATES]
|
|
1988
2011
|
},
|
|
1989
2012
|
{
|
|
1990
2013
|
value: "in",
|
|
1991
2014
|
label: "In",
|
|
1992
|
-
types: ["text", "number"]
|
|
1993
|
-
set: true
|
|
2015
|
+
types: ["text", "number"]
|
|
1994
2016
|
},
|
|
1995
2017
|
{
|
|
1996
2018
|
value: "notIn",
|
|
1997
2019
|
label: "Not in",
|
|
1998
|
-
types: ["text", "number"]
|
|
1999
|
-
set: true
|
|
2020
|
+
types: ["text", "number"]
|
|
2000
2021
|
},
|
|
2001
2022
|
{
|
|
2002
2023
|
value: "isBlank",
|
|
2003
2024
|
label: "Is blank",
|
|
2004
|
-
types: ALL
|
|
2005
|
-
valueless: true
|
|
2025
|
+
types: ALL
|
|
2006
2026
|
},
|
|
2007
2027
|
{
|
|
2008
2028
|
value: "isNotBlank",
|
|
2009
2029
|
label: "Is not blank",
|
|
2010
|
-
types: ALL
|
|
2011
|
-
valueless: true
|
|
2030
|
+
types: ALL
|
|
2012
2031
|
}
|
|
2013
|
-
]
|
|
2032
|
+
].map((op) => ({
|
|
2033
|
+
...op,
|
|
2034
|
+
...isValuelessOperator(op.value) ? { valueless: true } : {},
|
|
2035
|
+
...isSetOperator(op.value) ? { set: true } : {},
|
|
2036
|
+
...isRangeOperator(op.value) ? { range: true } : {}
|
|
2037
|
+
}));
|
|
2014
2038
|
new Map(OPERATORS.map((op) => [op.value, op]));
|
|
2015
2039
|
//#endregion
|
|
2016
2040
|
//#region src/expressions/parse.ts
|
|
@@ -2552,6 +2576,13 @@ var GENERATED_UI_SURFACE = {
|
|
|
2552
2576
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
2553
2577
|
"group": "behavior"
|
|
2554
2578
|
},
|
|
2579
|
+
{
|
|
2580
|
+
"key": "block",
|
|
2581
|
+
"label": "Block",
|
|
2582
|
+
"type": "boolean",
|
|
2583
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
2584
|
+
"group": "appearance"
|
|
2585
|
+
},
|
|
2555
2586
|
{
|
|
2556
2587
|
"key": "error",
|
|
2557
2588
|
"label": "Error",
|
|
@@ -2674,6 +2705,13 @@ var GENERATED_UI_SURFACE = {
|
|
|
2674
2705
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
2675
2706
|
"group": "behavior"
|
|
2676
2707
|
},
|
|
2708
|
+
{
|
|
2709
|
+
"key": "block",
|
|
2710
|
+
"label": "Block",
|
|
2711
|
+
"type": "boolean",
|
|
2712
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
2713
|
+
"group": "appearance"
|
|
2714
|
+
},
|
|
2677
2715
|
{
|
|
2678
2716
|
"key": "error",
|
|
2679
2717
|
"label": "Error",
|
|
@@ -2809,6 +2847,14 @@ var GENERATED_UI_SURFACE = {
|
|
|
2809
2847
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
2810
2848
|
"group": "behavior"
|
|
2811
2849
|
},
|
|
2850
|
+
{
|
|
2851
|
+
"key": "block",
|
|
2852
|
+
"label": "Block",
|
|
2853
|
+
"type": "boolean",
|
|
2854
|
+
"default": false,
|
|
2855
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
2856
|
+
"group": "appearance"
|
|
2857
|
+
},
|
|
2812
2858
|
{
|
|
2813
2859
|
"key": "error",
|
|
2814
2860
|
"label": "Error",
|
|
@@ -3039,6 +3085,13 @@ var GENERATED_UI_SURFACE = {
|
|
|
3039
3085
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
3040
3086
|
"group": "behavior"
|
|
3041
3087
|
},
|
|
3088
|
+
{
|
|
3089
|
+
"key": "block",
|
|
3090
|
+
"label": "Block",
|
|
3091
|
+
"type": "boolean",
|
|
3092
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
3093
|
+
"group": "appearance"
|
|
3094
|
+
},
|
|
3042
3095
|
{
|
|
3043
3096
|
"key": "error",
|
|
3044
3097
|
"label": "Error",
|
|
@@ -3214,6 +3267,14 @@ var GENERATED_UI_SURFACE = {
|
|
|
3214
3267
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
3215
3268
|
"group": "behavior"
|
|
3216
3269
|
},
|
|
3270
|
+
{
|
|
3271
|
+
"key": "block",
|
|
3272
|
+
"label": "Block",
|
|
3273
|
+
"type": "boolean",
|
|
3274
|
+
"default": false,
|
|
3275
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
3276
|
+
"group": "appearance"
|
|
3277
|
+
},
|
|
3217
3278
|
{
|
|
3218
3279
|
"key": "error",
|
|
3219
3280
|
"label": "Error",
|
|
@@ -3438,6 +3499,14 @@ var GENERATED_UI_SURFACE = {
|
|
|
3438
3499
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
3439
3500
|
"group": "behavior"
|
|
3440
3501
|
},
|
|
3502
|
+
{
|
|
3503
|
+
"key": "block",
|
|
3504
|
+
"label": "Block",
|
|
3505
|
+
"type": "boolean",
|
|
3506
|
+
"default": false,
|
|
3507
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
3508
|
+
"group": "appearance"
|
|
3509
|
+
},
|
|
3441
3510
|
{
|
|
3442
3511
|
"key": "error",
|
|
3443
3512
|
"label": "Error",
|
|
@@ -3612,6 +3681,14 @@ var GENERATED_UI_SURFACE = {
|
|
|
3612
3681
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
3613
3682
|
"group": "behavior"
|
|
3614
3683
|
},
|
|
3684
|
+
{
|
|
3685
|
+
"key": "block",
|
|
3686
|
+
"label": "Block",
|
|
3687
|
+
"type": "boolean",
|
|
3688
|
+
"default": false,
|
|
3689
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
3690
|
+
"group": "appearance"
|
|
3691
|
+
},
|
|
3615
3692
|
{
|
|
3616
3693
|
"key": "error",
|
|
3617
3694
|
"label": "Error",
|
|
@@ -3763,6 +3840,13 @@ var GENERATED_UI_SURFACE = {
|
|
|
3763
3840
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
3764
3841
|
"group": "behavior"
|
|
3765
3842
|
},
|
|
3843
|
+
{
|
|
3844
|
+
"key": "block",
|
|
3845
|
+
"label": "Block",
|
|
3846
|
+
"type": "boolean",
|
|
3847
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
3848
|
+
"group": "appearance"
|
|
3849
|
+
},
|
|
3766
3850
|
{
|
|
3767
3851
|
"key": "error",
|
|
3768
3852
|
"label": "Error",
|
|
@@ -3898,6 +3982,13 @@ var GENERATED_UI_SURFACE = {
|
|
|
3898
3982
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
3899
3983
|
"group": "behavior"
|
|
3900
3984
|
},
|
|
3985
|
+
{
|
|
3986
|
+
"key": "block",
|
|
3987
|
+
"label": "Block",
|
|
3988
|
+
"type": "boolean",
|
|
3989
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
3990
|
+
"group": "appearance"
|
|
3991
|
+
},
|
|
3901
3992
|
{
|
|
3902
3993
|
"key": "error",
|
|
3903
3994
|
"label": "Error",
|
|
@@ -4049,6 +4140,14 @@ var GENERATED_UI_SURFACE = {
|
|
|
4049
4140
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
4050
4141
|
"group": "behavior"
|
|
4051
4142
|
},
|
|
4143
|
+
{
|
|
4144
|
+
"key": "block",
|
|
4145
|
+
"label": "Block",
|
|
4146
|
+
"type": "boolean",
|
|
4147
|
+
"default": false,
|
|
4148
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
4149
|
+
"group": "appearance"
|
|
4150
|
+
},
|
|
4052
4151
|
{
|
|
4053
4152
|
"key": "error",
|
|
4054
4153
|
"label": "Error",
|
|
@@ -4770,6 +4869,14 @@ var GENERATED_UI_SURFACE = {
|
|
|
4770
4869
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
4771
4870
|
"group": "behavior"
|
|
4772
4871
|
},
|
|
4872
|
+
{
|
|
4873
|
+
"key": "block",
|
|
4874
|
+
"label": "Block",
|
|
4875
|
+
"type": "boolean",
|
|
4876
|
+
"default": false,
|
|
4877
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
4878
|
+
"group": "appearance"
|
|
4879
|
+
},
|
|
4773
4880
|
{
|
|
4774
4881
|
"key": "error",
|
|
4775
4882
|
"label": "Error",
|
|
@@ -4944,6 +5051,14 @@ var GENERATED_UI_SURFACE = {
|
|
|
4944
5051
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
4945
5052
|
"group": "behavior"
|
|
4946
5053
|
},
|
|
5054
|
+
{
|
|
5055
|
+
"key": "block",
|
|
5056
|
+
"label": "Block",
|
|
5057
|
+
"type": "boolean",
|
|
5058
|
+
"default": false,
|
|
5059
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
5060
|
+
"group": "appearance"
|
|
5061
|
+
},
|
|
4947
5062
|
{
|
|
4948
5063
|
"key": "error",
|
|
4949
5064
|
"label": "Error",
|
|
@@ -5103,6 +5218,14 @@ var GENERATED_UI_SURFACE = {
|
|
|
5103
5218
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
5104
5219
|
"group": "behavior"
|
|
5105
5220
|
},
|
|
5221
|
+
{
|
|
5222
|
+
"key": "block",
|
|
5223
|
+
"label": "Block",
|
|
5224
|
+
"type": "boolean",
|
|
5225
|
+
"default": false,
|
|
5226
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
5227
|
+
"group": "appearance"
|
|
5228
|
+
},
|
|
5106
5229
|
{
|
|
5107
5230
|
"key": "error",
|
|
5108
5231
|
"label": "Error",
|
|
@@ -5252,6 +5375,14 @@ var GENERATED_UI_SURFACE = {
|
|
|
5252
5375
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
5253
5376
|
"group": "behavior"
|
|
5254
5377
|
},
|
|
5378
|
+
{
|
|
5379
|
+
"key": "block",
|
|
5380
|
+
"label": "Block",
|
|
5381
|
+
"type": "boolean",
|
|
5382
|
+
"default": false,
|
|
5383
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
5384
|
+
"group": "appearance"
|
|
5385
|
+
},
|
|
5255
5386
|
{
|
|
5256
5387
|
"key": "error",
|
|
5257
5388
|
"label": "Error",
|
|
@@ -5434,6 +5565,13 @@ var GENERATED_UI_SURFACE = {
|
|
|
5434
5565
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
5435
5566
|
"group": "behavior"
|
|
5436
5567
|
},
|
|
5568
|
+
{
|
|
5569
|
+
"key": "block",
|
|
5570
|
+
"label": "Block",
|
|
5571
|
+
"type": "boolean",
|
|
5572
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
5573
|
+
"group": "appearance"
|
|
5574
|
+
},
|
|
5437
5575
|
{
|
|
5438
5576
|
"key": "error",
|
|
5439
5577
|
"label": "Error",
|
|
@@ -5568,6 +5706,13 @@ var GENERATED_UI_SURFACE = {
|
|
|
5568
5706
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
5569
5707
|
"group": "behavior"
|
|
5570
5708
|
},
|
|
5709
|
+
{
|
|
5710
|
+
"key": "block",
|
|
5711
|
+
"label": "Block",
|
|
5712
|
+
"type": "boolean",
|
|
5713
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
5714
|
+
"group": "appearance"
|
|
5715
|
+
},
|
|
5571
5716
|
{
|
|
5572
5717
|
"key": "error",
|
|
5573
5718
|
"label": "Error",
|
|
@@ -5719,6 +5864,14 @@ var GENERATED_UI_SURFACE = {
|
|
|
5719
5864
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
5720
5865
|
"group": "behavior"
|
|
5721
5866
|
},
|
|
5867
|
+
{
|
|
5868
|
+
"key": "block",
|
|
5869
|
+
"label": "Block",
|
|
5870
|
+
"type": "boolean",
|
|
5871
|
+
"default": false,
|
|
5872
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
5873
|
+
"group": "appearance"
|
|
5874
|
+
},
|
|
5722
5875
|
{
|
|
5723
5876
|
"key": "error",
|
|
5724
5877
|
"label": "Error",
|
|
@@ -5901,6 +6054,13 @@ var GENERATED_UI_SURFACE = {
|
|
|
5901
6054
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
5902
6055
|
"group": "behavior"
|
|
5903
6056
|
},
|
|
6057
|
+
{
|
|
6058
|
+
"key": "block",
|
|
6059
|
+
"label": "Block",
|
|
6060
|
+
"type": "boolean",
|
|
6061
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
6062
|
+
"group": "appearance"
|
|
6063
|
+
},
|
|
5904
6064
|
{
|
|
5905
6065
|
"key": "error",
|
|
5906
6066
|
"label": "Error",
|
|
@@ -6082,6 +6242,13 @@ var GENERATED_UI_SURFACE = {
|
|
|
6082
6242
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
6083
6243
|
"group": "behavior"
|
|
6084
6244
|
},
|
|
6245
|
+
{
|
|
6246
|
+
"key": "block",
|
|
6247
|
+
"label": "Block",
|
|
6248
|
+
"type": "boolean",
|
|
6249
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
6250
|
+
"group": "appearance"
|
|
6251
|
+
},
|
|
6085
6252
|
{
|
|
6086
6253
|
"key": "error",
|
|
6087
6254
|
"label": "Error",
|
|
@@ -6269,6 +6436,13 @@ var GENERATED_UI_SURFACE = {
|
|
|
6269
6436
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
6270
6437
|
"group": "behavior"
|
|
6271
6438
|
},
|
|
6439
|
+
{
|
|
6440
|
+
"key": "block",
|
|
6441
|
+
"label": "Block",
|
|
6442
|
+
"type": "boolean",
|
|
6443
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
6444
|
+
"group": "appearance"
|
|
6445
|
+
},
|
|
6272
6446
|
{
|
|
6273
6447
|
"key": "error",
|
|
6274
6448
|
"label": "Error",
|
|
@@ -6830,6 +7004,14 @@ var GENERATED_UI_SURFACE = {
|
|
|
6830
7004
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
6831
7005
|
"group": "behavior"
|
|
6832
7006
|
},
|
|
7007
|
+
{
|
|
7008
|
+
"key": "block",
|
|
7009
|
+
"label": "Block",
|
|
7010
|
+
"type": "boolean",
|
|
7011
|
+
"default": false,
|
|
7012
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
7013
|
+
"group": "appearance"
|
|
7014
|
+
},
|
|
6833
7015
|
{
|
|
6834
7016
|
"key": "error",
|
|
6835
7017
|
"label": "Error",
|
|
@@ -7504,6 +7686,14 @@ var GENERATED_UI_SURFACE = {
|
|
|
7504
7686
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
7505
7687
|
"group": "behavior"
|
|
7506
7688
|
},
|
|
7689
|
+
{
|
|
7690
|
+
"key": "block",
|
|
7691
|
+
"label": "Block",
|
|
7692
|
+
"type": "boolean",
|
|
7693
|
+
"default": false,
|
|
7694
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
7695
|
+
"group": "appearance"
|
|
7696
|
+
},
|
|
7507
7697
|
{
|
|
7508
7698
|
"key": "error",
|
|
7509
7699
|
"label": "Error",
|
|
@@ -7905,6 +8095,13 @@ var GENERATED_UI_SURFACE = {
|
|
|
7905
8095
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
7906
8096
|
"group": "behavior"
|
|
7907
8097
|
},
|
|
8098
|
+
{
|
|
8099
|
+
"key": "block",
|
|
8100
|
+
"label": "Block",
|
|
8101
|
+
"type": "boolean",
|
|
8102
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
8103
|
+
"group": "appearance"
|
|
8104
|
+
},
|
|
7908
8105
|
{
|
|
7909
8106
|
"key": "error",
|
|
7910
8107
|
"label": "Error",
|
|
@@ -8201,6 +8398,13 @@ var GENERATED_UI_SURFACE = {
|
|
|
8201
8398
|
"description": "Marks the control invalid (`aria-invalid` + error styling).",
|
|
8202
8399
|
"group": "behavior"
|
|
8203
8400
|
},
|
|
8401
|
+
{
|
|
8402
|
+
"key": "block",
|
|
8403
|
+
"label": "Block",
|
|
8404
|
+
"type": "boolean",
|
|
8405
|
+
"description": "Fill the container instead of the control's own default width. A default width is right for a control sitting on its own; in a form grid a row of inputs each stopping at a different width reads as broken.",
|
|
8406
|
+
"group": "appearance"
|
|
8407
|
+
},
|
|
8204
8408
|
{
|
|
8205
8409
|
"key": "error",
|
|
8206
8410
|
"label": "Error",
|
|
@@ -8418,6 +8622,20 @@ var GENERATED_UI_SURFACE = {
|
|
|
8418
8622
|
"type": "boolean",
|
|
8419
8623
|
"group": "common"
|
|
8420
8624
|
},
|
|
8625
|
+
{
|
|
8626
|
+
"key": "groupBy",
|
|
8627
|
+
"label": "Group By",
|
|
8628
|
+
"type": "json",
|
|
8629
|
+
"description": "Group the rows by these column ids, outermost first - `['region', 'country']` rolls country up inside region. ```svelte <SvGrid {data} {columns} {features} groupBy={['department']} /> ``` The prop seeds the group-by list and re-applies whenever it changes, so it works both as initial state and as a controlled value. The column menu and `api.setGroupBy()` write the same state; a change from either survives until this prop's own value changes. Ignored when `treeData` is set - a row cannot be both a hierarchy node and bucketed under a group banner.",
|
|
8630
|
+
"group": "common"
|
|
8631
|
+
},
|
|
8632
|
+
{
|
|
8633
|
+
"key": "expanded",
|
|
8634
|
+
"label": "Expanded",
|
|
8635
|
+
"type": "json",
|
|
8636
|
+
"description": "Which group / tree rows are expanded, keyed by row id. Expansion is owned by the engine by default; pass this prop to hoist it (saved views, \"expand everything on load\", persisted UI state). Like `groupBy` it seeds the state and re-applies whenever it changes. Group row ids are built from the grouping path, not the display label: `group_department_Engineering`, and one level deeper `group_department_Engineering_role_Senior`. Tree rows key off the engine's row id instead (set `getRowId` to make that your own id). Prefer capturing the map from `onExpandedChange` over hand-building these keys.",
|
|
8637
|
+
"group": "common"
|
|
8638
|
+
},
|
|
8421
8639
|
{
|
|
8422
8640
|
"key": "groupFooters",
|
|
8423
8641
|
"label": "Group Footers",
|
|
@@ -8817,6 +9035,13 @@ var GENERATED_UI_SURFACE = {
|
|
|
8817
9035
|
"description": "The sort state to start in - `{ id, desc }` entries. Use with `externalSort` when the initial ordering is decided server-side (e.g. a URL `?sort=` param read in a SvelteKit `load`), so the header sort indicators match the already- sorted data on first render. Applied once at mount; user sorting takes over.",
|
|
8818
9036
|
"group": "common"
|
|
8819
9037
|
},
|
|
9038
|
+
{
|
|
9039
|
+
"key": "initialAdvancedFilter",
|
|
9040
|
+
"label": "Initial Advanced Filter",
|
|
9041
|
+
"type": "json",
|
|
9042
|
+
"description": "The advanced-filter expression to start in (Pro). Applied once at mount; change it afterwards through `api.setAdvancedFilter()`. Filtering only happens once `@svgrid/enterprise`'s `enableAdvancedFilter()` has registered a compiler - without it the expression is stored and reported but no rows are removed, so the free grid degrades to a no-op rather than to a wrong row set.",
|
|
9043
|
+
"group": "common"
|
|
9044
|
+
},
|
|
8820
9045
|
{
|
|
8821
9046
|
"key": "externalFilter",
|
|
8822
9047
|
"label": "External Filter",
|
|
@@ -8967,6 +9192,12 @@ var GENERATED_UI_SURFACE = {
|
|
|
8967
9192
|
"prop": "onPivotModeChange",
|
|
8968
9193
|
"description": "Fired when the in-grid Pivot toggle flips `pivotMode`."
|
|
8969
9194
|
},
|
|
9195
|
+
{
|
|
9196
|
+
"key": "expandedChange",
|
|
9197
|
+
"label": "Expanded Change",
|
|
9198
|
+
"prop": "onExpandedChange",
|
|
9199
|
+
"description": "Fired whenever the expanded set changes - chevron clicks, `api.setRowExpanded()`, `expandAllGroups()` / `collapseAllGroups()`. Receives the full next map, so it can be written straight back into `expanded` for a controlled setup."
|
|
9200
|
+
},
|
|
8970
9201
|
{
|
|
8971
9202
|
"key": "paginationChange",
|
|
8972
9203
|
"label": "Pagination Change",
|
|
@@ -8997,6 +9228,12 @@ var GENERATED_UI_SURFACE = {
|
|
|
8997
9228
|
"prop": "onSortingChange",
|
|
8998
9229
|
"description": "Fires whenever the sort clauses change. Receives the new array of `{ id, desc }` entries. Pair with `externalSort={true}` when the consumer wants to own the row ordering."
|
|
8999
9230
|
},
|
|
9231
|
+
{
|
|
9232
|
+
"key": "advancedFilterChange",
|
|
9233
|
+
"label": "Advanced Filter Change",
|
|
9234
|
+
"prop": "onAdvancedFilterChange",
|
|
9235
|
+
"description": "Fires whenever the advanced-filter expression changes, whatever changed it: `api.setAdvancedFilter()`, `clearAllFilters()`, or the toolbar's clear control. The panel that authors the expression is mounted by you, outside the grid, so it cannot see a change the grid made on its own. Without this, clearing from the toolbar leaves that panel showing a filter the grid is no longer applying. Feed this back into the panel's `expression` prop to keep them agreeing."
|
|
9236
|
+
},
|
|
9000
9237
|
{
|
|
9001
9238
|
"key": "filtersChange",
|
|
9002
9239
|
"label": "Filters Change",
|
|
@@ -11064,6 +11301,18 @@ function gridApiSettableProps() {
|
|
|
11064
11301
|
}
|
|
11065
11302
|
//#endregion
|
|
11066
11303
|
//#region src/studio/project.ts
|
|
11304
|
+
/**
|
|
11305
|
+
* Studio project model - the declarative spine the visual designer edits and the
|
|
11306
|
+
* codegen emits. A project is a multi-entity app: `entities` (the data model) +
|
|
11307
|
+
* `screens` (one per entity by default), where a screen is an ordered list of
|
|
11308
|
+
* data-bound `blocks` (grid, form, chart, dashboard, KPI, master-detail, lookup).
|
|
11309
|
+
*
|
|
11310
|
+
* Pure + node-safe (lives in the `./studio` subtree - `.js` imports, no Svelte,
|
|
11311
|
+
* no `sources/`), mirroring the immutable-ops style of `schema-designer.ts`:
|
|
11312
|
+
* every mutation returns a NEW project so Svelte reactivity + undo stay simple.
|
|
11313
|
+
* Block-config unions are defined here (not imported from `sources/`) to keep the
|
|
11314
|
+
* module resolvable under node16.
|
|
11315
|
+
*/
|
|
11067
11316
|
/** Block kinds allowed inside a Tabs / Accordion container: the controller-free,
|
|
11068
11317
|
* `allRows`-driven display blocks (no grid / form / master-detail, which need the
|
|
11069
11318
|
* screen controller). `component` covers any UI-kit component added by key. */
|
|
@@ -11652,13 +11901,18 @@ function setJob(project, id, job) {
|
|
|
11652
11901
|
jobs: next.length ? next : void 0
|
|
11653
11902
|
};
|
|
11654
11903
|
}
|
|
11655
|
-
/** The designer's block palette, in menu order.
|
|
11656
|
-
*
|
|
11904
|
+
/** The designer's block palette, in menu order. A grid owns edit-in-popup and a
|
|
11905
|
+
* record panel edits the selected row, so the standalone Form block is the one
|
|
11906
|
+
* that creates: a form on its own page, with no grid behind it. */
|
|
11657
11907
|
var blockPalette = [
|
|
11658
11908
|
{
|
|
11659
11909
|
kind: "grid",
|
|
11660
11910
|
label: "Grid"
|
|
11661
11911
|
},
|
|
11912
|
+
{
|
|
11913
|
+
kind: "form",
|
|
11914
|
+
label: "Form"
|
|
11915
|
+
},
|
|
11662
11916
|
{
|
|
11663
11917
|
kind: "chart",
|
|
11664
11918
|
label: "Chart",
|
|
@@ -11779,7 +12033,8 @@ function defaultBlockConfig(kind, entity) {
|
|
|
11779
12033
|
};
|
|
11780
12034
|
case "form": return {
|
|
11781
12035
|
kind,
|
|
11782
|
-
presentation: "
|
|
12036
|
+
presentation: "inline",
|
|
12037
|
+
afterSave: "reset"
|
|
11783
12038
|
};
|
|
11784
12039
|
case "chart": {
|
|
11785
12040
|
const measure = pickMeasure(entity);
|
|
@@ -12398,6 +12653,403 @@ function removeEntity(project, name) {
|
|
|
12398
12653
|
screens: project.screens.filter((s) => s.entity !== name)
|
|
12399
12654
|
};
|
|
12400
12655
|
}
|
|
12656
|
+
/**
|
|
12657
|
+
* The fields a form actually renders, in schema order. Arranging anything else
|
|
12658
|
+
* would be a lie: a field hidden from the form cannot be put in a section and
|
|
12659
|
+
* then appear there.
|
|
12660
|
+
*/
|
|
12661
|
+
function formFieldNames(schema) {
|
|
12662
|
+
return schemaToFormFields(schema).map((f) => f.field);
|
|
12663
|
+
}
|
|
12664
|
+
/**
|
|
12665
|
+
* The sections as a builder should show them, plus the fields no section claims.
|
|
12666
|
+
*
|
|
12667
|
+
* Sections name their fields by string, so a rename, a delete, or hiding a field
|
|
12668
|
+
* from the form can leave a name behind. Those are dropped here rather than
|
|
12669
|
+
* drawn as ghosts, and a field in no section comes back in `unassigned` - which
|
|
12670
|
+
* is where the form itself puts it too, in a trailing untitled group.
|
|
12671
|
+
*/
|
|
12672
|
+
function formPlan(schema, override) {
|
|
12673
|
+
const inForm = formFieldNames(schema);
|
|
12674
|
+
const known = new Set(inForm);
|
|
12675
|
+
const source = override ?? schema.form?.sections ?? [];
|
|
12676
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12677
|
+
return {
|
|
12678
|
+
sections: source.map((section) => {
|
|
12679
|
+
const fields = section.fields.filter((f) => {
|
|
12680
|
+
if (!known.has(f) || seen.has(f)) return false;
|
|
12681
|
+
seen.add(f);
|
|
12682
|
+
return true;
|
|
12683
|
+
});
|
|
12684
|
+
return {
|
|
12685
|
+
...section,
|
|
12686
|
+
fields
|
|
12687
|
+
};
|
|
12688
|
+
}),
|
|
12689
|
+
unassigned: inForm.filter((f) => !seen.has(f))
|
|
12690
|
+
};
|
|
12691
|
+
}
|
|
12692
|
+
/** Replace an entity's form layout. `undefined` drops it back to the default. */
|
|
12693
|
+
function setEntityForm(project, entityName, form) {
|
|
12694
|
+
return mapEntity(project, entityName, (schema) => {
|
|
12695
|
+
const next = { ...schema };
|
|
12696
|
+
if (form && (form.columns !== void 0 || form.sections?.length)) next.form = form;
|
|
12697
|
+
else delete next.form;
|
|
12698
|
+
return next;
|
|
12699
|
+
});
|
|
12700
|
+
}
|
|
12701
|
+
/** Set the form's column count, or clear it back to the default. */
|
|
12702
|
+
function setFormColumns(project, entityName, columns) {
|
|
12703
|
+
const schema = entityOf(project, entityName);
|
|
12704
|
+
if (!schema) return project;
|
|
12705
|
+
return setEntityForm(project, entityName, {
|
|
12706
|
+
...schema.form,
|
|
12707
|
+
columns
|
|
12708
|
+
});
|
|
12709
|
+
}
|
|
12710
|
+
/** Append a section. New sections start empty - fields move in afterwards. */
|
|
12711
|
+
function addFormSection(project, entityName, title = "Section") {
|
|
12712
|
+
const schema = entityOf(project, entityName);
|
|
12713
|
+
if (!schema) return project;
|
|
12714
|
+
return setEntityForm(project, entityName, {
|
|
12715
|
+
...schema.form,
|
|
12716
|
+
sections: [...schema.form?.sections ?? [], {
|
|
12717
|
+
title,
|
|
12718
|
+
fields: []
|
|
12719
|
+
}]
|
|
12720
|
+
});
|
|
12721
|
+
}
|
|
12722
|
+
/** Patch one section. An out-of-range index is a no-op rather than an error. */
|
|
12723
|
+
function updateFormSection(project, entityName, index, patch) {
|
|
12724
|
+
const schema = entityOf(project, entityName);
|
|
12725
|
+
const sections = schema?.form?.sections;
|
|
12726
|
+
if (!sections?.[index]) return project;
|
|
12727
|
+
const next = sections.map((s, i) => {
|
|
12728
|
+
if (i !== index) return s;
|
|
12729
|
+
const merged = {
|
|
12730
|
+
...s,
|
|
12731
|
+
...patch
|
|
12732
|
+
};
|
|
12733
|
+
if (!merged.title) delete merged.title;
|
|
12734
|
+
if (!merged.description) delete merged.description;
|
|
12735
|
+
if (!merged.visibleWhen) delete merged.visibleWhen;
|
|
12736
|
+
if (!merged.columns) delete merged.columns;
|
|
12737
|
+
if (!merged.collapsible) {
|
|
12738
|
+
delete merged.collapsible;
|
|
12739
|
+
delete merged.collapsed;
|
|
12740
|
+
}
|
|
12741
|
+
if (!merged.collapsed) delete merged.collapsed;
|
|
12742
|
+
return merged;
|
|
12743
|
+
});
|
|
12744
|
+
return setEntityForm(project, entityName, {
|
|
12745
|
+
...schema.form,
|
|
12746
|
+
sections: next
|
|
12747
|
+
});
|
|
12748
|
+
}
|
|
12749
|
+
/**
|
|
12750
|
+
* Remove a section. Its fields stay in the form - they fall back to the trailing
|
|
12751
|
+
* untitled group, so deleting a heading never deletes the questions under it.
|
|
12752
|
+
*/
|
|
12753
|
+
function removeFormSection(project, entityName, index) {
|
|
12754
|
+
const schema = entityOf(project, entityName);
|
|
12755
|
+
const sections = schema?.form?.sections;
|
|
12756
|
+
if (!sections?.[index]) return project;
|
|
12757
|
+
return setEntityForm(project, entityName, {
|
|
12758
|
+
...schema.form,
|
|
12759
|
+
sections: sections.filter((_, i) => i !== index)
|
|
12760
|
+
});
|
|
12761
|
+
}
|
|
12762
|
+
/** Reorder the sections themselves. */
|
|
12763
|
+
function moveFormSection(project, entityName, from, to) {
|
|
12764
|
+
const schema = entityOf(project, entityName);
|
|
12765
|
+
const sections = schema?.form?.sections;
|
|
12766
|
+
if (!sections?.[from] || to < 0 || to >= sections.length || from === to) return project;
|
|
12767
|
+
const next = [...sections];
|
|
12768
|
+
next.splice(to, 0, next.splice(from, 1)[0]);
|
|
12769
|
+
return setEntityForm(project, entityName, {
|
|
12770
|
+
...schema.form,
|
|
12771
|
+
sections: next
|
|
12772
|
+
});
|
|
12773
|
+
}
|
|
12774
|
+
/**
|
|
12775
|
+
* Move a field into a section at a position, or out of every section when
|
|
12776
|
+
* `toSection` is null. The field is pulled out of wherever it was first, so it
|
|
12777
|
+
* can never end up in two sections - which would render the control twice.
|
|
12778
|
+
*/
|
|
12779
|
+
function moveFormField(project, entityName, field, toSection, toIndex = Number.MAX_SAFE_INTEGER) {
|
|
12780
|
+
const schema = entityOf(project, entityName);
|
|
12781
|
+
if (!schema || !formFieldNames(schema).includes(field)) return project;
|
|
12782
|
+
const sections = schema.form?.sections ?? [];
|
|
12783
|
+
if (toSection !== null && !sections[toSection]) return project;
|
|
12784
|
+
const stripped = sections.map((s) => ({
|
|
12785
|
+
...s,
|
|
12786
|
+
fields: s.fields.filter((f) => f !== field)
|
|
12787
|
+
}));
|
|
12788
|
+
if (toSection === null) return setEntityForm(project, entityName, {
|
|
12789
|
+
...schema.form,
|
|
12790
|
+
sections: stripped
|
|
12791
|
+
});
|
|
12792
|
+
const target = stripped[toSection];
|
|
12793
|
+
const at = Math.max(0, Math.min(toIndex, target.fields.length));
|
|
12794
|
+
const fields = [...target.fields];
|
|
12795
|
+
fields.splice(at, 0, field);
|
|
12796
|
+
return setEntityForm(project, entityName, {
|
|
12797
|
+
...schema.form,
|
|
12798
|
+
sections: stripped.map((s, i) => i === toSection ? {
|
|
12799
|
+
...s,
|
|
12800
|
+
fields
|
|
12801
|
+
} : s)
|
|
12802
|
+
});
|
|
12803
|
+
}
|
|
12804
|
+
/**
|
|
12805
|
+
* Move several fields at once, as one contiguous block in the order given.
|
|
12806
|
+
*
|
|
12807
|
+
* Not a loop of {@link moveFormField}: each single move both shifts the target
|
|
12808
|
+
* indices and re-resolves the plan, so a loop lands the group scattered or
|
|
12809
|
+
* reversed. Strip every named field first, then splice the whole group at the
|
|
12810
|
+
* index computed against the stripped target.
|
|
12811
|
+
*
|
|
12812
|
+
* Unknown and hidden-from-form names are dropped, duplicates keep their first
|
|
12813
|
+
* position, and an input that resolves to nothing returns the project
|
|
12814
|
+
* unchanged (same reference), so an undo stack never records a no-op.
|
|
12815
|
+
*/
|
|
12816
|
+
function moveFormFields(project, entityName, fields, toSection, toIndex = Number.MAX_SAFE_INTEGER) {
|
|
12817
|
+
const schema = entityOf(project, entityName);
|
|
12818
|
+
if (!schema) return project;
|
|
12819
|
+
const movable = new Set(formFieldNames(schema));
|
|
12820
|
+
const group = [];
|
|
12821
|
+
for (const f of fields) if (movable.has(f) && !group.includes(f)) group.push(f);
|
|
12822
|
+
if (!group.length) return project;
|
|
12823
|
+
const sections = schema.form?.sections ?? [];
|
|
12824
|
+
if (toSection !== null && !sections[toSection]) return project;
|
|
12825
|
+
const moving = new Set(group);
|
|
12826
|
+
const stripped = sections.map((s) => ({
|
|
12827
|
+
...s,
|
|
12828
|
+
fields: s.fields.filter((f) => !moving.has(f))
|
|
12829
|
+
}));
|
|
12830
|
+
if (toSection === null) return setEntityForm(project, entityName, {
|
|
12831
|
+
...schema.form,
|
|
12832
|
+
sections: stripped
|
|
12833
|
+
});
|
|
12834
|
+
const target = stripped[toSection];
|
|
12835
|
+
const at = Math.max(0, Math.min(toIndex, target.fields.length));
|
|
12836
|
+
const next = [...target.fields];
|
|
12837
|
+
next.splice(at, 0, ...group);
|
|
12838
|
+
return setEntityForm(project, entityName, {
|
|
12839
|
+
...schema.form,
|
|
12840
|
+
sections: stripped.map((s, i) => i === toSection ? {
|
|
12841
|
+
...s,
|
|
12842
|
+
fields: next
|
|
12843
|
+
} : s)
|
|
12844
|
+
});
|
|
12845
|
+
}
|
|
12846
|
+
/**
|
|
12847
|
+
* Set (or clear) a field's value-driven conditions. Each is a `PredicateExpr`,
|
|
12848
|
+
* so it stays data all the way into the generated app - see `EntityField.when`.
|
|
12849
|
+
*/
|
|
12850
|
+
function setFieldConditions(project, entityName, field, when) {
|
|
12851
|
+
return mapEntity(project, entityName, (schema) => ({
|
|
12852
|
+
...schema,
|
|
12853
|
+
fields: schema.fields.map((f) => {
|
|
12854
|
+
if (f.field !== field) return f;
|
|
12855
|
+
const next = { ...f };
|
|
12856
|
+
if (when?.visible || when?.disabled || when?.required) next.when = {
|
|
12857
|
+
...when.visible && { visible: when.visible },
|
|
12858
|
+
...when.disabled && { disabled: when.disabled },
|
|
12859
|
+
...when.required && { required: when.required }
|
|
12860
|
+
};
|
|
12861
|
+
else delete next.when;
|
|
12862
|
+
return next;
|
|
12863
|
+
})
|
|
12864
|
+
}));
|
|
12865
|
+
}
|
|
12866
|
+
/**
|
|
12867
|
+
* Patch one field of one entity. The form builder edits an entity that is not
|
|
12868
|
+
* necessarily the selected screen's, so it needs the project-level door rather
|
|
12869
|
+
* than the schema-level `updateField`.
|
|
12870
|
+
*
|
|
12871
|
+
* Deliberately shallow: `type` changes belong to the schema designer, which also
|
|
12872
|
+
* has to clean up `options` / `relation` when the type moves.
|
|
12873
|
+
*/
|
|
12874
|
+
function updateEntityField(project, entityName, field, patch) {
|
|
12875
|
+
return mapEntity(project, entityName, (schema) => ({
|
|
12876
|
+
...schema,
|
|
12877
|
+
fields: schema.fields.map((f) => f.field === field ? {
|
|
12878
|
+
...f,
|
|
12879
|
+
...patch
|
|
12880
|
+
} : f)
|
|
12881
|
+
}));
|
|
12882
|
+
}
|
|
12883
|
+
/**
|
|
12884
|
+
* Patch a field's form presentation (`EntityField.input`). Merges rather than
|
|
12885
|
+
* replaces, and a key set to `undefined` or `''` is removed - so clearing a
|
|
12886
|
+
* placeholder leaves no empty string behind, and emptying the last key drops
|
|
12887
|
+
* `input` itself rather than persisting `input: {}`.
|
|
12888
|
+
*/
|
|
12889
|
+
function setFieldInput(project, entityName, field, patch) {
|
|
12890
|
+
return mapEntity(project, entityName, (schema) => ({
|
|
12891
|
+
...schema,
|
|
12892
|
+
fields: schema.fields.map((f) => {
|
|
12893
|
+
if (f.field !== field) return f;
|
|
12894
|
+
const input = { ...f.input };
|
|
12895
|
+
for (const [key, value] of Object.entries(patch)) if (value === void 0 || value === "") delete input[key];
|
|
12896
|
+
else input[key] = value;
|
|
12897
|
+
const next = { ...f };
|
|
12898
|
+
if (Object.keys(input).length) next.input = input;
|
|
12899
|
+
else delete next.input;
|
|
12900
|
+
return next;
|
|
12901
|
+
})
|
|
12902
|
+
}));
|
|
12903
|
+
}
|
|
12904
|
+
/**
|
|
12905
|
+
* Show or hide a field on one surface, keeping the other surface's answer.
|
|
12906
|
+
* `hidden: true` means both, so it is expanded before one half is changed -
|
|
12907
|
+
* otherwise hiding a field from the form would silently un-hide its column.
|
|
12908
|
+
*/
|
|
12909
|
+
function setFieldHidden(project, entityName, field, surface, hidden) {
|
|
12910
|
+
return mapEntity(project, entityName, (schema) => ({
|
|
12911
|
+
...schema,
|
|
12912
|
+
fields: schema.fields.map((f) => {
|
|
12913
|
+
if (f.field !== field) return f;
|
|
12914
|
+
const merged = {
|
|
12915
|
+
...f.hidden === true ? {
|
|
12916
|
+
grid: true,
|
|
12917
|
+
form: true
|
|
12918
|
+
} : { ...f.hidden || {} },
|
|
12919
|
+
[surface]: hidden
|
|
12920
|
+
};
|
|
12921
|
+
const next = { ...f };
|
|
12922
|
+
if (merged.grid && merged.form) next.hidden = true;
|
|
12923
|
+
else if (merged.grid || merged.form) next.hidden = {
|
|
12924
|
+
...merged.grid && { grid: true },
|
|
12925
|
+
...merged.form && { form: true }
|
|
12926
|
+
};
|
|
12927
|
+
else delete next.hidden;
|
|
12928
|
+
return next;
|
|
12929
|
+
})
|
|
12930
|
+
}));
|
|
12931
|
+
}
|
|
12932
|
+
/**
|
|
12933
|
+
* The form controls worth offering for a field type. A form builder that listed
|
|
12934
|
+
* every editor for every type would be a wall of mostly-wrong choices - a date
|
|
12935
|
+
* field has no business rendering as a colour picker. The first entry is what
|
|
12936
|
+
* the field renders as when `input.editorType` is unset.
|
|
12937
|
+
*/
|
|
12938
|
+
function formControlsFor(type) {
|
|
12939
|
+
switch (type) {
|
|
12940
|
+
case "number": return [
|
|
12941
|
+
"number",
|
|
12942
|
+
"slider",
|
|
12943
|
+
"rating",
|
|
12944
|
+
"text"
|
|
12945
|
+
];
|
|
12946
|
+
case "boolean": return ["checkbox"];
|
|
12947
|
+
case "date":
|
|
12948
|
+
case "dateString": return ["date", "date-native"];
|
|
12949
|
+
case "datetime": return [
|
|
12950
|
+
"datetime",
|
|
12951
|
+
"datetime-native",
|
|
12952
|
+
"time"
|
|
12953
|
+
];
|
|
12954
|
+
case "enum": return [
|
|
12955
|
+
"select",
|
|
12956
|
+
"rich-select",
|
|
12957
|
+
"list",
|
|
12958
|
+
"chips",
|
|
12959
|
+
"autocomplete"
|
|
12960
|
+
];
|
|
12961
|
+
case "relation": return ["select", "autocomplete"];
|
|
12962
|
+
case "json": return ["textarea", "text"];
|
|
12963
|
+
default: return [
|
|
12964
|
+
"text",
|
|
12965
|
+
"textarea",
|
|
12966
|
+
"password",
|
|
12967
|
+
"phone",
|
|
12968
|
+
"country",
|
|
12969
|
+
"mask",
|
|
12970
|
+
"color",
|
|
12971
|
+
"autocomplete",
|
|
12972
|
+
"chips"
|
|
12973
|
+
];
|
|
12974
|
+
}
|
|
12975
|
+
}
|
|
12976
|
+
function formControlSettings(control, type) {
|
|
12977
|
+
const kind = control ?? formControlsFor(type)[0];
|
|
12978
|
+
if (kind === "mask") return ["mask"];
|
|
12979
|
+
if (kind === "slider" || kind === "rating") return ["range", "step"];
|
|
12980
|
+
if (kind === "number" || type === "number" && kind !== "text") return [
|
|
12981
|
+
"range",
|
|
12982
|
+
"step",
|
|
12983
|
+
"precision",
|
|
12984
|
+
"affix"
|
|
12985
|
+
];
|
|
12986
|
+
return [];
|
|
12987
|
+
}
|
|
12988
|
+
/**
|
|
12989
|
+
* A first pass at sectioning an unarranged form, by what the field names say
|
|
12990
|
+
* they are. Studio's promise is a working app in a few clicks, and an entity of
|
|
12991
|
+
* fifteen fields in one flat list is not that.
|
|
12992
|
+
*
|
|
12993
|
+
* A guess, offered once: it returns sections for a builder to drop in and then
|
|
12994
|
+
* edit, and it never invents a group for a form small enough not to need one.
|
|
12995
|
+
*/
|
|
12996
|
+
var SECTION_HINTS = [
|
|
12997
|
+
{
|
|
12998
|
+
title: "Contact",
|
|
12999
|
+
match: /^(email|phone|mobile|fax|website|url|contact)/i
|
|
13000
|
+
},
|
|
13001
|
+
{
|
|
13002
|
+
title: "Address",
|
|
13003
|
+
match: /(address|street|city|state|province|zip|postcode|postal|country|region)/i
|
|
13004
|
+
},
|
|
13005
|
+
{
|
|
13006
|
+
title: "Money",
|
|
13007
|
+
match: /(amount|price|cost|total|revenue|mrr|arr|salary|budget|value|balance|fee|tax|discount)/i
|
|
13008
|
+
},
|
|
13009
|
+
{
|
|
13010
|
+
title: "Dates",
|
|
13011
|
+
match: /(date|_at$|At$|deadline|due|expires|starts|ends)/i
|
|
13012
|
+
},
|
|
13013
|
+
{
|
|
13014
|
+
title: "Notes",
|
|
13015
|
+
match: /(note|notes|comment|comments|description|summary|remark)/i
|
|
13016
|
+
}
|
|
13017
|
+
];
|
|
13018
|
+
function suggestFormSections(schema) {
|
|
13019
|
+
const names = formFieldNames(schema);
|
|
13020
|
+
if (names.length < 6) return [];
|
|
13021
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
13022
|
+
const rest = [];
|
|
13023
|
+
for (const name of names) {
|
|
13024
|
+
const hint = SECTION_HINTS.find((h) => h.match.test(name));
|
|
13025
|
+
if (!hint) {
|
|
13026
|
+
rest.push(name);
|
|
13027
|
+
continue;
|
|
13028
|
+
}
|
|
13029
|
+
const bucket = buckets.get(hint.title);
|
|
13030
|
+
if (bucket) bucket.push(name);
|
|
13031
|
+
else buckets.set(hint.title, [name]);
|
|
13032
|
+
}
|
|
13033
|
+
const sections = [];
|
|
13034
|
+
for (const [title, fields] of buckets) if (fields.length > 1) sections.push({
|
|
13035
|
+
title,
|
|
13036
|
+
fields
|
|
13037
|
+
});
|
|
13038
|
+
else rest.push(...fields);
|
|
13039
|
+
if (!sections.length) return [];
|
|
13040
|
+
return rest.length ? [{
|
|
13041
|
+
title: "Details",
|
|
13042
|
+
fields: rest
|
|
13043
|
+
}, ...sections] : sections;
|
|
13044
|
+
}
|
|
13045
|
+
/** Apply a change to one entity's schema, leaving the project alone if it is unknown. */
|
|
13046
|
+
function mapEntity(project, entityName, fn) {
|
|
13047
|
+
if (!entityOf(project, entityName)) return project;
|
|
13048
|
+
return {
|
|
13049
|
+
...project,
|
|
13050
|
+
entities: project.entities.map((e) => e.name === entityName ? fn(e) : e)
|
|
13051
|
+
};
|
|
13052
|
+
}
|
|
12401
13053
|
/** Append a screen, making its id AND route unique against the existing set. */
|
|
12402
13054
|
function appendScreen(project, base, keyBase) {
|
|
12403
13055
|
const ids = new Set(project.screens.map((s) => s.id));
|
|
@@ -13550,7 +14202,13 @@ function validateProject(project) {
|
|
|
13550
14202
|
block: b.id
|
|
13551
14203
|
});
|
|
13552
14204
|
const c = b.config;
|
|
13553
|
-
if (c.kind === "
|
|
14205
|
+
if (c.kind === "form") {
|
|
14206
|
+
if (!s.entity) issues.push(at("A Form block needs a screen bound to an entity.", "error"));
|
|
14207
|
+
if (c.afterSave === "navigate") {
|
|
14208
|
+
if (!c.navigateTo) issues.push(at("The form is set to open a screen after saving, but no screen is chosen."));
|
|
14209
|
+
else if (!project.screens.some((x) => x.id === c.navigateTo)) issues.push(at(`The form opens a missing screen "${c.navigateTo}" after saving.`, "error"));
|
|
14210
|
+
}
|
|
14211
|
+
} else if (c.kind === "master-detail") {
|
|
13554
14212
|
if (!c.childEntity || !c.foreignKey) issues.push(at("Master/detail needs a child entity + foreign key."));
|
|
13555
14213
|
else if (!entityOf(project, c.childEntity)) issues.push(at(`Master/detail points at a missing child entity "${c.childEntity}".`));
|
|
13556
14214
|
} else if (c.kind === "tree") {
|
|
@@ -15130,7 +15788,7 @@ function hasFieldConditions(schema) {
|
|
|
15130
15788
|
*
|
|
15131
15789
|
* `version.test.ts` asserts this matches `package.json`, so the two cannot drift.
|
|
15132
15790
|
*/
|
|
15133
|
-
var SVGRID_VERSION = "2.6.
|
|
15791
|
+
var SVGRID_VERSION = "2.6.2";
|
|
15134
15792
|
//#endregion
|
|
15135
15793
|
//#region src/studio/emit-project.ts
|
|
15136
15794
|
var has = (blocks, kind) => blocks.some((b) => b.config.kind === kind);
|
|
@@ -15528,9 +16186,35 @@ ${panels}
|
|
|
15528
16186
|
}
|
|
15529
16187
|
case "lookup": return ` <div ${span}${cls}><!-- lookup (${cfg.field}): shown in the edit form --></div>`;
|
|
15530
16188
|
case "component": return componentBlockMarkup(block, cfg, ctx.handleNames?.get(block.id), rowsExpr);
|
|
16189
|
+
case "form": return createFormMarkup(entity, schemaVar, block, cfg);
|
|
15531
16190
|
default: return "";
|
|
15532
16191
|
}
|
|
15533
16192
|
}
|
|
16193
|
+
/**
|
|
16194
|
+
* A standalone create form: blank, always on the page, submits a new row.
|
|
16195
|
+
*
|
|
16196
|
+
* Keyed on `formSaves` so a successful create remounts the panel with empty
|
|
16197
|
+
* values - the panel seeds itself from `row` once, so without the key the
|
|
16198
|
+
* previous entry would still be sitting in the fields.
|
|
16199
|
+
*/
|
|
16200
|
+
function createFormMarkup(entity, schemaVar, block, cfg) {
|
|
16201
|
+
const span = wrapperStyle(block);
|
|
16202
|
+
const cls = wrapperClass(block);
|
|
16203
|
+
const attrs = [
|
|
16204
|
+
`schema={${schemaVar}}`,
|
|
16205
|
+
"row={null}",
|
|
16206
|
+
"presentation=\"inline\""
|
|
16207
|
+
];
|
|
16208
|
+
attrs.push(`title={${jsStr(cfg.title ?? `New ${entity.label ?? entity.name}`)}}`);
|
|
16209
|
+
if (cfg.submitLabel) attrs.push(`submitLabel={${jsStr(cfg.submitLabel)}}`);
|
|
16210
|
+
if (cfg.width && cfg.width !== "md") attrs.push(`formSize=${jsStr(cfg.width)}`);
|
|
16211
|
+
return ` <div ${span}${cls}>${cfg.afterSave === "navigate" ? "" : `
|
|
16212
|
+
{#if formSaves}<p class="st-form__done" role="status">Saved. Add another below.</p>{/if}`}
|
|
16213
|
+
{#key formSaves}
|
|
16214
|
+
<SvGridEditPanel ${attrs.join(" ")} onSubmit={createRecord} />
|
|
16215
|
+
{/key}
|
|
16216
|
+
</div>`;
|
|
16217
|
+
}
|
|
15534
16218
|
/** Emits a UI-kit component block (see `UI_COMPONENT_REGISTRY`): a literal
|
|
15535
16219
|
* `<SvXxx .../>` tag carrying its configured "chrome" props + optional text
|
|
15536
16220
|
* content. Entity-agnostic - used both from `blockMarkup` (mixed onto an
|
|
@@ -16707,14 +17391,14 @@ function screenPage(schema, rawSchema, screen, resolve, rawResolve, accessEnable
|
|
|
16707
17391
|
const codeGridBlockId = firstGridBlockId(screen);
|
|
16708
17392
|
const handleNames = handleNameMap(screen);
|
|
16709
17393
|
const codeWire = codeEnabled ? codeWiring(screen, n.type, void 0) : null;
|
|
16710
|
-
const
|
|
17394
|
+
const createForm = blocks.map((b) => b.config).find((c) => c.kind === "form");
|
|
16711
17395
|
const gridConfigs = blocks.map((b) => b.config).filter((c) => c.kind === "grid");
|
|
16712
17396
|
const formGrid = gridConfigs.find((c) => c.editing === "form");
|
|
16713
17397
|
const hasEditAction = gridConfigs.some((c) => c.rowActions?.some((a) => a.kind === "edit"));
|
|
16714
17398
|
const hasRowActions = gridConfigs.some((c) => (c.rowActions?.length ?? 0) > 0);
|
|
16715
17399
|
const cellRenderKinds = new Set(gridConfigs.flatMap((c) => c.columns.filter((col) => col.show && col.cellType).map((col) => col.cellType.kind)));
|
|
16716
17400
|
const hasCellRenderers = cellRenderKinds.size > 0;
|
|
16717
|
-
const wantsForm = !!formGrid ||
|
|
17401
|
+
const wantsForm = !!formGrid || hasEditAction;
|
|
16718
17402
|
const gridPageSize = gridConfigs[0] ? gridConfigs[0].paginated !== false ? gridConfigs[0].pageSize ?? 10 : 1e3 : 10;
|
|
16719
17403
|
const formPres = formGrid?.formPresentation ?? "modal";
|
|
16720
17404
|
const formLayoutProps = editPanelLayoutProps(formGrid);
|
|
@@ -16722,7 +17406,7 @@ function screenPage(schema, rawSchema, screen, resolve, rawResolve, accessEnable
|
|
|
16722
17406
|
const hasFilter = has(blocks, "filter");
|
|
16723
17407
|
const hasRecord = has(blocks, "record");
|
|
16724
17408
|
const recordEditable = blocks.some((b) => b.config.kind === "record" && b.config.editable);
|
|
16725
|
-
const needsController = hasGrid || wantsForm || hasFilter || hasRecord;
|
|
17409
|
+
const needsController = hasGrid || wantsForm || hasFilter || hasRecord || !!createForm;
|
|
16726
17410
|
const rtSupabase = !ssrData && needsController && entSource?.kind === "supabase" && entSource.realtime === true;
|
|
16727
17411
|
const rtTable = rtSupabase ? entSource.table : "";
|
|
16728
17412
|
const hasAgg = has(allBlocks, "chart") || has(allBlocks, "dashboard") || has(allBlocks, "kpi") || has(allBlocks, "gauge") || has(allBlocks, "tree");
|
|
@@ -16790,7 +17474,7 @@ function screenPage(schema, rawSchema, screen, resolve, rawResolve, accessEnable
|
|
|
16790
17474
|
...childSourceVars,
|
|
16791
17475
|
...wantsForm ? [...lookupVars, "nextId"] : []
|
|
16792
17476
|
])].filter(Boolean);
|
|
16793
|
-
const usesGoto = blocks.some((b) => b.config.kind === "grid" && b.config.rowLink && routeById.has(b.config.rowLink.screen) || b.config.kind === "grid" && b.config.rowActions?.some((a) => a.kind === "navigate" && a.screen && routeById.has(a.screen)) || b.config.kind === "chart" && b.config.drillScreen && routeById.has(b.config.drillScreen) || (b.config.kind === "board" || b.config.kind === "calendar") && b.config.openScreen != null && routeById.has(b.config.openScreen) || b.config.kind === "master-detail" && b.config.linkScreen != null && routeById.has(b.config.linkScreen));
|
|
17477
|
+
const usesGoto = blocks.some((b) => b.config.kind === "grid" && b.config.rowLink && routeById.has(b.config.rowLink.screen) || b.config.kind === "grid" && b.config.rowActions?.some((a) => a.kind === "navigate" && a.screen && routeById.has(a.screen)) || b.config.kind === "chart" && b.config.drillScreen && routeById.has(b.config.drillScreen) || (b.config.kind === "board" || b.config.kind === "calendar") && b.config.openScreen != null && routeById.has(b.config.openScreen) || b.config.kind === "master-detail" && b.config.linkScreen != null && routeById.has(b.config.linkScreen) || b.config.kind === "form" && b.config.afterSave === "navigate" && b.config.navigateTo != null && routeById.has(b.config.navigateTo));
|
|
16794
17478
|
const applyUrlFilters = drillEnabled && needsController;
|
|
16795
17479
|
const filterableFieldNames = schema.fields.filter((f) => !f.primaryKey).map((f) => f.field);
|
|
16796
17480
|
const gatesUi = accessEnabled && (wantsForm || gridConfigs.some((c) => c.editing === "inline") || hasRowActions);
|
|
@@ -16877,6 +17561,15 @@ function screenPage(schema, rawSchema, screen, resolve, rawResolve, accessEnable
|
|
|
16877
17561
|
if (mode === 'create') { await controller.createRow({ [idField]: nextId('${n.idPrefix}'), ...values } as Partial<${n.type}>); controller.setPage(view.pageCount - 1) }
|
|
16878
17562
|
else if (id) { await controller.updateRow(id, values) }${submitBody}
|
|
16879
17563
|
editing = undefined${needsAllRows ? "\n await loadAll()" : ""}
|
|
17564
|
+
}`);
|
|
17565
|
+
}
|
|
17566
|
+
if (createForm) {
|
|
17567
|
+
const nav = createForm.afterSave === "navigate" && createForm.navigateTo ? routeById.get(createForm.navigateTo) : void 0;
|
|
17568
|
+
const after = nav ? `\n await goto('/${nav}')` : "";
|
|
17569
|
+
parts.push(`let formSaves = $state(0)
|
|
17570
|
+
async function createRecord({ values }: { mode: 'create' | 'edit'; id: string | null; values: Partial<${n.type}> }) {
|
|
17571
|
+
await controller.createRow({ [idField]: nextId('${n.idPrefix}'), ...values } as Partial<${n.type}>)${submitBody}
|
|
17572
|
+
formSaves += 1${after}
|
|
16880
17573
|
}`);
|
|
16881
17574
|
}
|
|
16882
17575
|
if (hasRecord) parts.push(`let selectedRecord = $state<${n.type} | null>(null)${recordEditable ? `
|
|
@@ -17303,14 +17996,19 @@ ${hint ? ` {#if !form?.errors?.[${key}]}<small class="sk-hint">${htmlEs
|
|
|
17303
17996
|
const ssrSections = layout?.sections?.length ? (() => {
|
|
17304
17997
|
const assigned = /* @__PURE__ */ new Set();
|
|
17305
17998
|
const groups = layout.sections.map((s) => {
|
|
17999
|
+
const names = [];
|
|
17306
18000
|
const items = s.fields.map((name) => {
|
|
17307
18001
|
assigned.add(name);
|
|
18002
|
+
names.push(name);
|
|
17308
18003
|
return blockFor(name);
|
|
17309
18004
|
}).filter(Boolean);
|
|
17310
18005
|
return {
|
|
17311
18006
|
title: s.title,
|
|
17312
18007
|
description: s.description,
|
|
17313
18008
|
columns: s.columns,
|
|
18009
|
+
collapsible: s.collapsible,
|
|
18010
|
+
collapsed: s.collapsed,
|
|
18011
|
+
names,
|
|
17314
18012
|
items
|
|
17315
18013
|
};
|
|
17316
18014
|
}).filter((g) => g.items.length);
|
|
@@ -17319,13 +18017,26 @@ ${hint ? ` {#if !form?.errors?.[${key}]}<small class="sk-hint">${htmlEs
|
|
|
17319
18017
|
title: void 0,
|
|
17320
18018
|
description: void 0,
|
|
17321
18019
|
columns: void 0,
|
|
18020
|
+
collapsible: false,
|
|
18021
|
+
collapsed: false,
|
|
18022
|
+
names: [],
|
|
17322
18023
|
items: rest
|
|
17323
18024
|
}] : groups;
|
|
17324
18025
|
})() : null;
|
|
17325
18026
|
const formCols = layout?.columns ?? 1;
|
|
17326
|
-
const fieldsMarkup = ssrSections ? ssrSections.map((g) =>
|
|
17327
|
-
|
|
17328
|
-
|
|
18027
|
+
const fieldsMarkup = ssrSections ? ssrSections.map((g) => {
|
|
18028
|
+
const inner = `${g.description ? ` <p class="sk-group__desc">${htmlEsc(g.description)}</p>\n` : ""}${g.items.join("\n")}`;
|
|
18029
|
+
if (g.collapsible && g.title) {
|
|
18030
|
+
const open = g.collapsed ? `{${JSON.stringify(g.names)}.some((f) => form?.errors?.[f])}` : "{true}";
|
|
18031
|
+
return ` <details class="sk-group sk-group--fold" style="--sk-cols: ${g.columns ?? formCols}" open=${open}>
|
|
18032
|
+
<summary>${htmlEsc(g.title)}</summary>
|
|
18033
|
+
${inner}
|
|
18034
|
+
</details>`;
|
|
18035
|
+
}
|
|
18036
|
+
return ` <fieldset class="sk-group" style="--sk-cols: ${g.columns ?? formCols}">
|
|
18037
|
+
${g.title ? ` <legend>${htmlEsc(g.title)}</legend>\n` : ""}${inner}
|
|
18038
|
+
</fieldset>`;
|
|
18039
|
+
}).join("\n") : ` <div class="sk-group" style="--sk-cols: ${formCols}">\n${fieldBlocks.join("\n")}\n </div>`;
|
|
17329
18040
|
const page = `<script lang="ts">
|
|
17330
18041
|
import { SvGrid, renderSnippet, type ColumnDef, type CellContext } from '@svgrid/grid'
|
|
17331
18042
|
import { schemaToColumns } from '@svgrid/enterprise'
|
|
@@ -17437,6 +18148,13 @@ ${facetCss} .sk-rowact { display: flex; gap: 10px; }
|
|
|
17437
18148
|
.sk-group + .sk-group { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--sg-border, #e2e8f0); }
|
|
17438
18149
|
.sk-group legend { grid-column: 1 / -1; padding: 0; font-size: 12px; font-weight: 700; letter-spacing: 0.02em; text-transform: uppercase; color: var(--sg-muted, #64748b); }
|
|
17439
18150
|
.sk-group__desc { grid-column: 1 / -1; margin: 0; font-size: 12px; color: var(--sg-muted, #64748b); }
|
|
18151
|
+
/* A foldable group is a native <details>, so it works with JavaScript off.
|
|
18152
|
+
display:grid on the element itself would lay the <summary> out as a grid
|
|
18153
|
+
item and break the disclosure, so the grid moves to [open] children. */
|
|
18154
|
+
.sk-group--fold { display: block; }
|
|
18155
|
+
.sk-group--fold > summary { grid-column: 1 / -1; margin-bottom: 12px; font-size: 13.5px; font-weight: 650; color: var(--sg-fg, #0f172a); cursor: pointer; list-style-position: inside; }
|
|
18156
|
+
.sk-group--fold[open] { display: grid; }
|
|
18157
|
+
.sk-group--fold[open] > summary { margin-bottom: 0; }
|
|
17440
18158
|
.sk-field--wide { grid-column: 1 / -1; }
|
|
17441
18159
|
.sk-hint { color: var(--sg-muted, #64748b); font-size: 11.5px; }
|
|
17442
18160
|
@media (max-width: 560px) { .sk-group { grid-template-columns: 1fr; } }
|
|
@@ -40770,4 +41488,4 @@ function checkLicenseKey(key, now = /* @__PURE__ */ new Date()) {
|
|
|
40770
41488
|
};
|
|
40771
41489
|
}
|
|
40772
41490
|
//#endregion
|
|
40773
|
-
export { CANVAS_COLS, CANVAS_GAP_PX, CANVAS_ROW_PX, CONTAINER_CHILD_KINDS, CONTAINER_DISPLAY_KINDS, CRUD_ACTIONS, DEFAULT_PORT, DRIVER_PACKAGE, FORM_SUBMIT, GRID_API_MEMBERS, GRID_CURATED_PROPS, GRID_EVENTS, GRID_PRESETS, MANAGED_END, MANAGED_START, ON_LOAD, PANE_LAYOUTS, STANDARD_UI_EVENTS, TAB_CHILD_KINDS, TRIGGER_EVENTS, UI_COMPONENT_REGISTRY, UserError, addAccordionBlock, addAccordionComponent, addAccordionSection, addBlock, addBlockAt, addComponentBlock, addCrudSuite, addEntity, addFreestandingScreen, addHandlerStep, addScreen, addScreenAction, addScreenFromTemplate, addStateVar, addTab, addTabBlock, addTabComponent, applyGridPreset, blockClassName, blockColumns, blockPalette, blockStyleCss, buildCanvasLayout, buildConnectionString, buildCopilotMessages, buildDockLayout, buildStudioBugReport, canvasOpts, canvasRectOf, changeSlot, checkLicenseKey, clickSlot, compileCondition, compileHandlerSteps, compileStep, compileTriggerStep, compileTriggerSteps, compileValue, componentHandleMembers, componentHandleName, componentHasBindings, countTableRows, createProject, crudAppFromSchemas, crudSuiteScreens, csvToEntity, ctxAmbientDts, ctxCompletions, dashScreen, defaultBlockConfig, defaultEntitySource, defaultScreenFor, defaultStudioTheme, deployCommands, detailScreen, detectDelimiter, disableScreenCode, dockOpts, dockPaneIds, dockPaneTitleOf, duplicateBlock, duplicateScreen, emitEntityModules, emitStudioApp, emitStudioAppBundle, emitStudioFragment, emitStudioProject, enableScreenCode, entityDataSource, entityOf, entityScreenPage, eventSlot, flattenBlocks, formScreen, generateRows, generateValue, getLiveDataSample, getSampleApp, getStarterDataset, getStudioTheme, gridApiSettableProps, gridColumns, gridConfig, gridOpts, gridPresetLabel, gridPropSurface, inferType, insertBlock, introspectDatabase, introspectDrizzle, introspectDrizzleAll, introspectJson, introspectOpenApi, introspectPrisma, introspectPrismaAll, isDarkTheme, isFileDialect, isPaneLayout, isProjectValid, isTenantScoped, isUserError, linkRelationLabels, listDatabaseTables, listScreen, liveDataSamples, mapSqlType, mergeBlockStyle, mergeManaged, missingEnvKeys, moveBlock, moveHandlerStep, parseConnectionString, parseCsv, parseProject, parseSelection, pickLabelField, prepareEntities, probeConnection, projectFromModelText, reconcileDock, redactConnectionString, refineField, refineFields, removeAccordionBlock, removeAccordionSection, removeBlock, removeEntity, removeScreen, removeScreenAction, removeStateVar, removeTab, removeTabBlock, renameAccordionSection, renameTab, reorderBlock, reorderScreen, reseedScreenDock, resolveDeployTarget, resolveIdField, resolveSchema, resolveSchemas, resolveThemeTokens, resolveThemeTokensFor, roleCanAction, roleCanScreen, rowSelectSlot, runStudioAdd, runStudioAddApp, runStudioInit, runtimeDeps, sampleApps, sanitizeClassName, sanitizeProject, sanitizeStudioProject, scaffold, scaffoldApp, schemaToColumns, schemaToFormFields, screenDataset, screenFromTemplate, screenHandles, screenLayoutOf, seedUsers, serializeProject, setAccordionMultiple, setAuth, setCanvasRect, setComponentBinding, setComponentName, setDataLayer, setDataSource, setDeployTarget, setDockPaneTitle, setEntityDataSource, setHandlerBody, setHandlerSteps, setJob, setLayoutOpts, setScreenDock, setScreenHandlersSource, setScreenLayout, setScreenRenderGrid, setScreenRenderMode, setShell, setTenancy, setTheme, setThemePreset, setTrigger, skipUserOwned, splitOpts, ssrEligible, ssrScreenShape, stackOpts, starterDatasets, starterProject, stateInitExpr, stateTsType, statusPills, stepsToCode, studioDeployInfo, studioThemes, summarizeVerify, syncDockPanes, tenantField, themeStyleString, triggersOf, uiComponentSpec, updateBlock, updateEntity, updateHandlerStep, updateScreen, updateStateVar, validateProject, verifyScaffold, withSsrDefaults };
|
|
41491
|
+
export { CANVAS_COLS, CANVAS_GAP_PX, CANVAS_ROW_PX, CONTAINER_CHILD_KINDS, CONTAINER_DISPLAY_KINDS, CRUD_ACTIONS, DEFAULT_PORT, DRIVER_PACKAGE, FORM_SUBMIT, GRID_API_MEMBERS, GRID_CURATED_PROPS, GRID_EVENTS, GRID_PRESETS, MANAGED_END, MANAGED_START, ON_LOAD, PANE_LAYOUTS, STANDARD_UI_EVENTS, TAB_CHILD_KINDS, TRIGGER_EVENTS, UI_COMPONENT_REGISTRY, UserError, addAccordionBlock, addAccordionComponent, addAccordionSection, addBlock, addBlockAt, addComponentBlock, addCrudSuite, addEntity, addFormSection, addFreestandingScreen, addHandlerStep, addScreen, addScreenAction, addScreenFromTemplate, addStateVar, addTab, addTabBlock, addTabComponent, applyGridPreset, blockClassName, blockColumns, blockPalette, blockStyleCss, buildCanvasLayout, buildConnectionString, buildCopilotMessages, buildDockLayout, buildStudioBugReport, canvasOpts, canvasRectOf, changeSlot, checkLicenseKey, clickSlot, compileCondition, compileHandlerSteps, compileStep, compileTriggerStep, compileTriggerSteps, compileValue, componentHandleMembers, componentHandleName, componentHasBindings, countTableRows, createProject, crudAppFromSchemas, crudSuiteScreens, csvToEntity, ctxAmbientDts, ctxCompletions, dashScreen, defaultBlockConfig, defaultEntitySource, defaultScreenFor, defaultStudioTheme, deployCommands, detailScreen, detectDelimiter, disableScreenCode, dockOpts, dockPaneIds, dockPaneTitleOf, duplicateBlock, duplicateScreen, emitEntityModules, emitStudioApp, emitStudioAppBundle, emitStudioFragment, emitStudioProject, enableScreenCode, entityDataSource, entityOf, entityScreenPage, eventSlot, flattenBlocks, formControlSettings, formControlsFor, formPlan, formScreen, generateRows, generateValue, getLiveDataSample, getSampleApp, getStarterDataset, getStudioTheme, gridApiSettableProps, gridColumns, gridConfig, gridOpts, gridPresetLabel, gridPropSurface, inferType, insertBlock, introspectDatabase, introspectDrizzle, introspectDrizzleAll, introspectJson, introspectOpenApi, introspectPrisma, introspectPrismaAll, isDarkTheme, isFieldHidden, isFileDialect, isPaneLayout, isProjectValid, isTenantScoped, isUserError, linkRelationLabels, listDatabaseTables, listScreen, liveDataSamples, mapSqlType, mergeBlockStyle, mergeManaged, missingEnvKeys, moveBlock, moveFormField, moveFormFields, moveFormSection, moveHandlerStep, parseConnectionString, parseCsv, parseProject, parseSelection, pickLabelField, prepareEntities, probeConnection, projectFromModelText, reconcileDock, redactConnectionString, refineField, refineFields, removeAccordionBlock, removeAccordionSection, removeBlock, removeEntity, removeFormSection, removeScreen, removeScreenAction, removeStateVar, removeTab, removeTabBlock, renameAccordionSection, renameTab, reorderBlock, reorderScreen, reseedScreenDock, resolveDeployTarget, resolveIdField, resolveSchema, resolveSchemas, resolveThemeTokens, resolveThemeTokensFor, roleCanAction, roleCanScreen, rowSelectSlot, runStudioAdd, runStudioAddApp, runStudioInit, runtimeDeps, sampleApps, sanitizeClassName, sanitizeProject, sanitizeStudioProject, scaffold, scaffoldApp, schemaToColumns, schemaToFormFields, screenDataset, screenFromTemplate, screenHandles, screenLayoutOf, seedUsers, serializeProject, setAccordionMultiple, setAuth, setCanvasRect, setComponentBinding, setComponentName, setDataLayer, setDataSource, setDeployTarget, setDockPaneTitle, setEntityDataSource, setEntityForm, setFieldConditions, setFieldHidden, setFieldInput, setFormColumns, setHandlerBody, setHandlerSteps, setJob, setLayoutOpts, setScreenDock, setScreenHandlersSource, setScreenLayout, setScreenRenderGrid, setScreenRenderMode, setShell, setTenancy, setTheme, setThemePreset, setTrigger, skipUserOwned, splitOpts, ssrEligible, ssrScreenShape, stackOpts, starterDatasets, starterProject, stateInitExpr, stateTsType, statusPills, stepsToCode, studioDeployInfo, studioThemes, suggestFormSections, summarizeVerify, syncDockPanes, tenantField, themeStyleString, triggersOf, uiComponentSpec, updateBlock, updateEntity, updateEntityField, updateFormSection, updateHandlerStep, updateScreen, updateStateVar, validateProject, verifyScaffold, withSsrDefaults };
|