@qnc/qnc_data_tables 1.3.1 → 1.3.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.
Files changed (85) hide show
  1. package/dist/bound_stored_value.d.ts +39 -0
  2. package/dist/bound_stored_value.js +135 -0
  3. package/dist/bound_stored_value.js.map +1 -0
  4. package/dist/bound_stored_value.ts +158 -0
  5. package/dist/column_manager.d.ts +45 -0
  6. package/dist/column_manager.js +125 -0
  7. package/dist/column_manager.js.map +1 -0
  8. package/dist/column_manager.ts +160 -0
  9. package/dist/column_resizing.d.ts +3 -0
  10. package/dist/column_resizing.js +31 -0
  11. package/dist/column_resizing.js.map +1 -0
  12. package/dist/column_resizing.ts +52 -0
  13. package/dist/column_sorting.d.ts +11 -0
  14. package/dist/column_sorting.js +54 -0
  15. package/dist/column_sorting.js.map +1 -0
  16. package/dist/column_sorting.ts +63 -0
  17. package/dist/conditionally_wrapped_element.d.ts +5 -0
  18. package/dist/conditionally_wrapped_element.js +15 -0
  19. package/dist/conditionally_wrapped_element.js.map +1 -0
  20. package/dist/conditionally_wrapped_element.ts +17 -0
  21. package/dist/create_mithril_app.d.ts +3 -0
  22. package/dist/create_mithril_app.js +26 -0
  23. package/dist/create_mithril_app.js.map +1 -0
  24. package/dist/create_mithril_app.ts +35 -0
  25. package/dist/create_style.d.ts +4 -0
  26. package/dist/create_style.js +10 -0
  27. package/dist/create_style.js.map +1 -0
  28. package/dist/create_style.ts +10 -0
  29. package/dist/custom_element.d.ts +23 -0
  30. package/dist/custom_element.js +64 -0
  31. package/dist/custom_element.js.map +1 -0
  32. package/dist/custom_element.ts +71 -0
  33. package/dist/event_names.d.ts +1 -0
  34. package/dist/event_names.js +2 -0
  35. package/dist/event_names.js.map +1 -0
  36. package/dist/event_names.ts +1 -0
  37. package/dist/index.d.ts +5 -0
  38. package/dist/index.js +5 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/index.ts +8 -0
  41. package/dist/mithril_view.d.ts +17 -0
  42. package/dist/mithril_view.js +548 -0
  43. package/dist/mithril_view.js.map +1 -0
  44. package/dist/mithril_view.ts +1138 -0
  45. package/dist/optional_storage.d.ts +6 -0
  46. package/dist/optional_storage.js +19 -0
  47. package/dist/optional_storage.js.map +1 -0
  48. package/dist/optional_storage.ts +23 -0
  49. package/dist/overflow_class_manager.d.ts +20 -0
  50. package/dist/overflow_class_manager.js +31 -0
  51. package/dist/overflow_class_manager.js.map +1 -0
  52. package/dist/overflow_class_manager.ts +40 -0
  53. package/dist/prepare_cell_html.d.ts +5 -0
  54. package/dist/prepare_cell_html.js +39 -0
  55. package/dist/prepare_cell_html.js.map +1 -0
  56. package/dist/prepare_cell_html.ts +48 -0
  57. package/dist/renderer.d.ts +16 -0
  58. package/dist/renderer.js +55 -0
  59. package/dist/renderer.js.map +1 -0
  60. package/dist/renderer.ts +89 -0
  61. package/dist/selection_fieldset_controller.d.ts +35 -0
  62. package/dist/selection_fieldset_controller.js +86 -0
  63. package/dist/selection_fieldset_controller.js.map +1 -0
  64. package/dist/selection_fieldset_controller.ts +104 -0
  65. package/dist/state_machine.d.ts +68 -0
  66. package/dist/state_machine.js +335 -0
  67. package/dist/state_machine.js.map +1 -0
  68. package/dist/state_machine.ts +458 -0
  69. package/dist/state_types.d.ts +62 -0
  70. package/dist/state_types.js +2 -0
  71. package/dist/state_types.js.map +1 -0
  72. package/dist/state_types.ts +84 -0
  73. package/dist/table_manager.d.ts +10 -0
  74. package/dist/table_manager.js +20 -0
  75. package/dist/table_manager.js.map +1 -0
  76. package/dist/table_manager.ts +32 -0
  77. package/dist/table_options.d.ts +177 -0
  78. package/dist/table_options.js +110 -0
  79. package/dist/table_options.js.map +1 -0
  80. package/dist/table_options.ts +150 -0
  81. package/dist/watched_mutable_value.d.ts +15 -0
  82. package/dist/watched_mutable_value.js +24 -0
  83. package/dist/watched_mutable_value.js.map +1 -0
  84. package/dist/watched_mutable_value.ts +23 -0
  85. package/package.json +1 -1
@@ -0,0 +1,177 @@
1
+ import * as ss from "superstruct";
2
+ declare const ColumnStruct: ss.Struct<{
3
+ key: string;
4
+ fixed: boolean;
5
+ display: string;
6
+ help_text: string;
7
+ enabled: boolean;
8
+ width: number;
9
+ sortable: boolean;
10
+ horizontal_alignment: "left" | "center" | "right" | "flex-start" | "flex-end" | "end" | "start";
11
+ data_vertical_alignment: "center" | "end" | "start" | "stretch";
12
+ }, {
13
+ /** used to persist settings in Storage; must be unique across a table */
14
+ key: ss.Struct<string, null>;
15
+ /** column title */
16
+ display: ss.Struct<string, null>;
17
+ help_text: ss.Struct<string, null>;
18
+ /** whether the column is _initially_ shown; user can enable/disable */
19
+ enabled: ss.Struct<boolean, null>;
20
+ /** if true, the column cannot be reordered or enabled/disabled by the user, and is "sticky" when scrolling horizontally */
21
+ fixed: ss.Struct<boolean, null>;
22
+ /** sets the _initial_ with, in px; it's user-resizable */
23
+ width: ss.Struct<number, null>;
24
+ /** whether or not the user can click the column header to sort by this column */
25
+ /** when the user is sorting by this column, we will automatically set sort key to column_asc-KEY or column-desc-KEY */
26
+ sortable: ss.Struct<boolean, null>;
27
+ /** effects BOTH headers and data cells; individual data cells can override */
28
+ horizontal_alignment: ss.Struct<"left" | "center" | "right" | "flex-start" | "flex-end" | "end" | "start", null>;
29
+ /** effects ONLY data cells (not header); individual data cells can override */
30
+ data_vertical_alignment: ss.Struct<"center" | "end" | "start" | "stretch", null>;
31
+ }>;
32
+ export type Column = ss.Infer<typeof ColumnStruct>;
33
+ declare const OptionalStorageStruct: ss.Struct<"localStorage" | "sessionStorage" | null, null>;
34
+ export type OptionalStorageChoice = ss.Infer<typeof OptionalStorageStruct>;
35
+ export declare function get_storage(type: OptionalStorageChoice): Storage | null;
36
+ /**
37
+ "ExtraSortFunctions" are NOT js functions.
38
+ They are DESCRIPTIONS of sort functions implemented by the backend.
39
+ The only thing the front-end does with them is display some kind of sort-picker.
40
+ */
41
+ declare const ExtraSortFunctionStruct: ss.Struct<{
42
+ key: string;
43
+ display: string;
44
+ help_text: string;
45
+ }, {
46
+ /** will be submitted to back-end */
47
+ key: ss.Struct<string, null>;
48
+ /** what to display in sort-picker */
49
+ display: ss.Struct<string, null>;
50
+ /** help text, in case `display` is not self-explanatory */
51
+ help_text: ss.Struct<string, null>;
52
+ }>;
53
+ export type ExtraSortFunction = ss.Infer<typeof ExtraSortFunctionStruct>;
54
+ declare const TableOptionsStruct: ss.Struct<{
55
+ columns: {
56
+ key: string;
57
+ fixed: boolean;
58
+ display: string;
59
+ help_text: string;
60
+ enabled: boolean;
61
+ width: number;
62
+ sortable: boolean;
63
+ horizontal_alignment: "left" | "center" | "right" | "flex-start" | "flex-end" | "end" | "start";
64
+ data_vertical_alignment: "center" | "end" | "start" | "stretch";
65
+ }[];
66
+ allow_selection: boolean;
67
+ api_url: string;
68
+ filter_form_id: string;
69
+ key_prefix: string;
70
+ page_size: number;
71
+ page_limit: number;
72
+ table_limit: number;
73
+ fill_last_page: boolean;
74
+ layout_storage: "localStorage" | "sessionStorage" | null;
75
+ navigation_storage: "localStorage" | "sessionStorage" | null;
76
+ selection_storage: "localStorage" | "sessionStorage" | null;
77
+ sort_storage: "localStorage" | "sessionStorage" | null;
78
+ extra_sort_functions: {
79
+ key: string;
80
+ display: string;
81
+ help_text: string;
82
+ }[];
83
+ default_sort: {
84
+ type: "column";
85
+ column_key: string;
86
+ direction: "reverse" | "forward";
87
+ } | {
88
+ type: "function";
89
+ function_key: string;
90
+ } | null;
91
+ }, {
92
+ columns: ss.Struct<{
93
+ key: string;
94
+ fixed: boolean;
95
+ display: string;
96
+ help_text: string;
97
+ enabled: boolean;
98
+ width: number;
99
+ sortable: boolean;
100
+ horizontal_alignment: "left" | "center" | "right" | "flex-start" | "flex-end" | "end" | "start";
101
+ data_vertical_alignment: "center" | "end" | "start" | "stretch";
102
+ }[], ss.Struct<{
103
+ key: string;
104
+ fixed: boolean;
105
+ display: string;
106
+ help_text: string;
107
+ enabled: boolean;
108
+ width: number;
109
+ sortable: boolean;
110
+ horizontal_alignment: "left" | "center" | "right" | "flex-start" | "flex-end" | "end" | "start";
111
+ data_vertical_alignment: "center" | "end" | "start" | "stretch";
112
+ }, {
113
+ /** used to persist settings in Storage; must be unique across a table */
114
+ key: ss.Struct<string, null>;
115
+ /** column title */
116
+ display: ss.Struct<string, null>;
117
+ help_text: ss.Struct<string, null>;
118
+ /** whether the column is _initially_ shown; user can enable/disable */
119
+ enabled: ss.Struct<boolean, null>;
120
+ /** if true, the column cannot be reordered or enabled/disabled by the user, and is "sticky" when scrolling horizontally */
121
+ fixed: ss.Struct<boolean, null>;
122
+ /** sets the _initial_ with, in px; it's user-resizable */
123
+ width: ss.Struct<number, null>;
124
+ /** whether or not the user can click the column header to sort by this column */
125
+ /** when the user is sorting by this column, we will automatically set sort key to column_asc-KEY or column-desc-KEY */
126
+ sortable: ss.Struct<boolean, null>;
127
+ /** effects BOTH headers and data cells; individual data cells can override */
128
+ horizontal_alignment: ss.Struct<"left" | "center" | "right" | "flex-start" | "flex-end" | "end" | "start", null>;
129
+ /** effects ONLY data cells (not header); individual data cells can override */
130
+ data_vertical_alignment: ss.Struct<"center" | "end" | "start" | "stretch", null>;
131
+ }>>;
132
+ allow_selection: ss.Struct<boolean, null>;
133
+ api_url: ss.Struct<string, null>;
134
+ filter_form_id: ss.Struct<string, null>;
135
+ key_prefix: ss.Struct<string, null>;
136
+ page_size: ss.Struct<number, null>;
137
+ page_limit: ss.Struct<number, null>;
138
+ table_limit: ss.Struct<number, null>;
139
+ fill_last_page: ss.Struct<boolean, null>;
140
+ /** Where table layout preferences (columns, column widths) are stored */
141
+ layout_storage: ss.Struct<"localStorage" | "sessionStorage" | null, null>;
142
+ /** where page number is stored */
143
+ navigation_storage: ss.Struct<"localStorage" | "sessionStorage" | null, null>;
144
+ /** where selection is stored */
145
+ selection_storage: ss.Struct<"localStorage" | "sessionStorage" | null, null>;
146
+ /** where sort order is stored */
147
+ sort_storage: ss.Struct<"localStorage" | "sessionStorage" | null, null>;
148
+ /** when non-empty, will cause a "sort widget" to be displayed in the paginator */
149
+ extra_sort_functions: ss.Struct<{
150
+ key: string;
151
+ display: string;
152
+ help_text: string;
153
+ }[], ss.Struct<{
154
+ key: string;
155
+ display: string;
156
+ help_text: string;
157
+ }, {
158
+ /** will be submitted to back-end */
159
+ key: ss.Struct<string, null>;
160
+ /** what to display in sort-picker */
161
+ display: ss.Struct<string, null>;
162
+ /** help text, in case `display` is not self-explanatory */
163
+ help_text: ss.Struct<string, null>;
164
+ }>>;
165
+ /** If null, front-end will arbitrarily choose one of the available sorting options */
166
+ default_sort: ss.Struct<{
167
+ type: "column";
168
+ column_key: string;
169
+ direction: "reverse" | "forward";
170
+ } | {
171
+ type: "function";
172
+ function_key: string;
173
+ } | null, null>;
174
+ }>;
175
+ export type TableOptions = ss.Infer<typeof TableOptionsStruct>;
176
+ export declare function read_options_from_json_string(json: string): TableOptions;
177
+ export {};
@@ -0,0 +1,110 @@
1
+ import * as ss from "superstruct";
2
+ import { assert_never } from "@qnc/type_utils";
3
+ function css_class_component() {
4
+ return ss.define("css_class_component", (value) => (typeof value == "string" && value.match(/^[\w-]*$/) !== null) ||
5
+ `Expected a string, but received: ${value}`);
6
+ }
7
+ const ColumnStruct = ss.object({
8
+ /** used to persist settings in Storage; must be unique across a table */
9
+ key: css_class_component(),
10
+ /** column title */
11
+ display: ss.string(),
12
+ help_text: ss.string(),
13
+ /** whether the column is _initially_ shown; user can enable/disable */
14
+ enabled: ss.boolean(),
15
+ /** if true, the column cannot be reordered or enabled/disabled by the user, and is "sticky" when scrolling horizontally */
16
+ fixed: ss.boolean(),
17
+ /** sets the _initial_ with, in px; it's user-resizable */
18
+ width: ss.number(),
19
+ /** whether or not the user can click the column header to sort by this column */
20
+ /** when the user is sorting by this column, we will automatically set sort key to column_asc-KEY or column-desc-KEY */
21
+ sortable: ss.boolean(),
22
+ /** effects BOTH headers and data cells; individual data cells can override */
23
+ horizontal_alignment: ss.defaulted(ss.union([
24
+ ss.literal("left"),
25
+ ss.literal("center"),
26
+ ss.literal("right"),
27
+ ss.literal("flex-start"),
28
+ ss.literal("flex-end"),
29
+ ss.literal("end"),
30
+ ss.literal("start"),
31
+ ]), "flex-start"),
32
+ /** effects ONLY data cells (not header); individual data cells can override */
33
+ data_vertical_alignment: ss.defaulted(ss.union([
34
+ ss.literal("stretch"),
35
+ ss.literal("center"),
36
+ ss.literal("start"),
37
+ ss.literal("end"),
38
+ ]), "center"),
39
+ });
40
+ const OptionalStorageStruct = ss.union([
41
+ ss.literal("localStorage"),
42
+ ss.literal("sessionStorage"),
43
+ ss.literal(null),
44
+ ]);
45
+ export function get_storage(type) {
46
+ if (type == "localStorage")
47
+ return localStorage;
48
+ if (type == "sessionStorage")
49
+ return sessionStorage;
50
+ if (type == null)
51
+ return null;
52
+ assert_never(type);
53
+ }
54
+ const SortStateStruct = ss.union([
55
+ ss.object({
56
+ type: ss.literal("column"),
57
+ column_key: ss.string(),
58
+ direction: ss.union([ss.literal("forward"), ss.literal("reverse")]),
59
+ }),
60
+ ss.object({
61
+ type: ss.literal("function"),
62
+ function_key: ss.string(),
63
+ }),
64
+ ]);
65
+ /**
66
+ "ExtraSortFunctions" are NOT js functions.
67
+ They are DESCRIPTIONS of sort functions implemented by the backend.
68
+ The only thing the front-end does with them is display some kind of sort-picker.
69
+ */
70
+ const ExtraSortFunctionStruct = ss.object({
71
+ /** will be submitted to back-end */
72
+ key: ss.string(),
73
+ /** what to display in sort-picker */
74
+ display: ss.string(),
75
+ /** help text, in case `display` is not self-explanatory */
76
+ help_text: ss.defaulted(ss.string(), ""),
77
+ });
78
+ const TableOptionsStruct = ss.object({
79
+ columns: ss.array(ColumnStruct),
80
+ allow_selection: ss.defaulted(ss.boolean(), false),
81
+ api_url: ss.defaulted(ss.string(), "."),
82
+ // If non-empty, MUST reference a <form> element on the page
83
+ filter_form_id: ss.defaulted(ss.string(), ""),
84
+ // Must be unique across all data tables on a given page (used in constructing CSS classes and Storage keys)
85
+ // Must be unique across all tables submitting to same api_url (used in constructing keys for backend communication)
86
+ // Must contain only alphanumerics, underscores, and hyphens
87
+ key_prefix: ss.defaulted(css_class_component(), "table-manager"),
88
+ page_size: ss.integer(),
89
+ page_limit: ss.integer(),
90
+ table_limit: ss.integer(),
91
+ // If last page of data has fewer rows than page_size and this is set, we'll add empty rows
92
+ // keeps layout/height more consistent, regardless of data
93
+ fill_last_page: ss.defaulted(ss.boolean(), true),
94
+ /** Where table layout preferences (columns, column widths) are stored */
95
+ layout_storage: ss.defaulted(OptionalStorageStruct, "localStorage"),
96
+ /** where page number is stored */
97
+ navigation_storage: ss.defaulted(OptionalStorageStruct, "sessionStorage"),
98
+ /** where selection is stored */
99
+ selection_storage: ss.defaulted(OptionalStorageStruct, "sessionStorage"),
100
+ /** where sort order is stored */
101
+ sort_storage: ss.defaulted(OptionalStorageStruct, "localStorage"),
102
+ /** when non-empty, will cause a "sort widget" to be displayed in the paginator */
103
+ extra_sort_functions: ss.defaulted(ss.array(ExtraSortFunctionStruct), []),
104
+ /** If null, front-end will arbitrarily choose one of the available sorting options */
105
+ default_sort: ss.defaulted(ss.union([SortStateStruct, ss.literal(null)]), null),
106
+ });
107
+ export function read_options_from_json_string(json) {
108
+ return ss.create(JSON.parse(json), TableOptionsStruct);
109
+ }
110
+ //# sourceMappingURL=table_options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table_options.js","sourceRoot":"","sources":["../src/table_options.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,150 @@
1
+ import * as ss from "superstruct";
2
+ import { assert_never } from "@qnc/type_utils";
3
+
4
+ function css_class_component(): ss.Struct<string, null> {
5
+ return ss.define(
6
+ "css_class_component",
7
+ (value) =>
8
+ (typeof value == "string" && value.match(/^[\w-]*$/) !== null) ||
9
+ `Expected a string, but received: ${value}`,
10
+ );
11
+ }
12
+
13
+ const ColumnStruct = ss.object({
14
+ /** used to persist settings in Storage; must be unique across a table */
15
+ key: css_class_component(),
16
+
17
+ /** column title */
18
+ display: ss.string(),
19
+
20
+ help_text: ss.string(),
21
+
22
+ /** whether the column is _initially_ shown; user can enable/disable */
23
+ enabled: ss.boolean(),
24
+
25
+ /** if true, the column cannot be reordered or enabled/disabled by the user, and is "sticky" when scrolling horizontally */
26
+ fixed: ss.boolean(),
27
+
28
+ /** sets the _initial_ with, in px; it's user-resizable */
29
+ width: ss.number(),
30
+
31
+ /** whether or not the user can click the column header to sort by this column */
32
+ /** when the user is sorting by this column, we will automatically set sort key to column_asc-KEY or column-desc-KEY */
33
+ sortable: ss.boolean(),
34
+
35
+ /** effects BOTH headers and data cells; individual data cells can override */
36
+ horizontal_alignment: ss.defaulted(
37
+ ss.union([
38
+ ss.literal("left"),
39
+ ss.literal("center"),
40
+ ss.literal("right"),
41
+ ss.literal("flex-start"),
42
+ ss.literal("flex-end"),
43
+ ss.literal("end"),
44
+ ss.literal("start"),
45
+ ]),
46
+ "flex-start",
47
+ ),
48
+
49
+ /** effects ONLY data cells (not header); individual data cells can override */
50
+ data_vertical_alignment: ss.defaulted(
51
+ ss.union([
52
+ ss.literal("stretch"),
53
+ ss.literal("center"),
54
+ ss.literal("start"),
55
+ ss.literal("end"),
56
+ ]),
57
+ "center",
58
+ ),
59
+ });
60
+ export type Column = ss.Infer<typeof ColumnStruct>;
61
+
62
+ const OptionalStorageStruct = ss.union([
63
+ ss.literal("localStorage"),
64
+ ss.literal("sessionStorage"),
65
+ ss.literal(null),
66
+ ]);
67
+ export type OptionalStorageChoice = ss.Infer<typeof OptionalStorageStruct>;
68
+
69
+ export function get_storage(type: OptionalStorageChoice): Storage | null {
70
+ if (type == "localStorage") return localStorage;
71
+ if (type == "sessionStorage") return sessionStorage;
72
+ if (type == null) return null;
73
+ assert_never(type);
74
+ }
75
+
76
+ const SortStateStruct = ss.union([
77
+ ss.object({
78
+ type: ss.literal("column"),
79
+ column_key: ss.string(),
80
+ direction: ss.union([ss.literal("forward"), ss.literal("reverse")]),
81
+ }),
82
+ ss.object({
83
+ type: ss.literal("function"),
84
+ function_key: ss.string(),
85
+ }),
86
+ ]);
87
+
88
+ /**
89
+ "ExtraSortFunctions" are NOT js functions.
90
+ They are DESCRIPTIONS of sort functions implemented by the backend.
91
+ The only thing the front-end does with them is display some kind of sort-picker.
92
+ */
93
+ const ExtraSortFunctionStruct = ss.object({
94
+ /** will be submitted to back-end */
95
+ key: ss.string(),
96
+ /** what to display in sort-picker */
97
+ display: ss.string(),
98
+ /** help text, in case `display` is not self-explanatory */
99
+ help_text: ss.defaulted(ss.string(), ""),
100
+ });
101
+ export type ExtraSortFunction = ss.Infer<typeof ExtraSortFunctionStruct>;
102
+
103
+ const TableOptionsStruct = ss.object({
104
+ columns: ss.array(ColumnStruct),
105
+ allow_selection: ss.defaulted(ss.boolean(), false),
106
+ api_url: ss.defaulted(ss.string(), "."),
107
+
108
+ // If non-empty, MUST reference a <form> element on the page
109
+ filter_form_id: ss.defaulted(ss.string(), ""),
110
+
111
+ // Must be unique across all data tables on a given page (used in constructing CSS classes and Storage keys)
112
+ // Must be unique across all tables submitting to same api_url (used in constructing keys for backend communication)
113
+ // Must contain only alphanumerics, underscores, and hyphens
114
+ key_prefix: ss.defaulted(css_class_component(), "table-manager"),
115
+
116
+ page_size: ss.integer(),
117
+ page_limit: ss.integer(),
118
+ table_limit: ss.integer(),
119
+
120
+ // If last page of data has fewer rows than page_size and this is set, we'll add empty rows
121
+ // keeps layout/height more consistent, regardless of data
122
+ fill_last_page: ss.defaulted(ss.boolean(), true),
123
+
124
+ /** Where table layout preferences (columns, column widths) are stored */
125
+ layout_storage: ss.defaulted(OptionalStorageStruct, "localStorage"),
126
+
127
+ /** where page number is stored */
128
+ navigation_storage: ss.defaulted(OptionalStorageStruct, "sessionStorage"),
129
+
130
+ /** where selection is stored */
131
+ selection_storage: ss.defaulted(OptionalStorageStruct, "sessionStorage"),
132
+
133
+ /** where sort order is stored */
134
+ sort_storage: ss.defaulted(OptionalStorageStruct, "localStorage"),
135
+
136
+ /** when non-empty, will cause a "sort widget" to be displayed in the paginator */
137
+ extra_sort_functions: ss.defaulted(ss.array(ExtraSortFunctionStruct), []),
138
+
139
+ /** If null, front-end will arbitrarily choose one of the available sorting options */
140
+ default_sort: ss.defaulted(
141
+ ss.union([SortStateStruct, ss.literal(null)]),
142
+ null,
143
+ ),
144
+ });
145
+
146
+ export type TableOptions = ss.Infer<typeof TableOptionsStruct>;
147
+
148
+ export function read_options_from_json_string(json: string): TableOptions {
149
+ return ss.create(JSON.parse(json), TableOptionsStruct);
150
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ Intended to hold values which must be determined by the view layer (ie. which depend on rendered layout)
3
+ and which affect other aspects of the UI.
4
+
5
+ Example: the UI renders an element, then checks if that element has overflow, then wants to toggle a class on that element in response to the check.
6
+
7
+ Your state machine / "data store" should own/create the WatchedMutableValue. It can pass it directly to the view layer, which is free to update it.
8
+ */
9
+ export declare class WatchedMutableValue<T> {
10
+ private value;
11
+ private onchange;
12
+ constructor(value: T, onchange: () => void);
13
+ get(): T;
14
+ set(value: T): void;
15
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ Intended to hold values which must be determined by the view layer (ie. which depend on rendered layout)
3
+ and which affect other aspects of the UI.
4
+
5
+ Example: the UI renders an element, then checks if that element has overflow, then wants to toggle a class on that element in response to the check.
6
+
7
+ Your state machine / "data store" should own/create the WatchedMutableValue. It can pass it directly to the view layer, which is free to update it.
8
+ */
9
+ export class WatchedMutableValue {
10
+ constructor(value, onchange) {
11
+ this.value = value;
12
+ this.onchange = onchange;
13
+ }
14
+ get() {
15
+ return this.value;
16
+ }
17
+ set(value) {
18
+ const changed = this.value != value;
19
+ this.value = value;
20
+ if (changed)
21
+ this.onchange();
22
+ }
23
+ }
24
+ //# sourceMappingURL=watched_mutable_value.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watched_mutable_value.js","sourceRoot":"","sources":["../src/watched_mutable_value.ts"],"names":[],"mappings":"AAAA;;;;;;;EAOE;AACF,MAAM,OAAO,mBAAmB;IAC5B,YACY,KAAQ,EACR,QAAoB;QADpB,UAAK,GAAL,KAAK,CAAG;QACR,aAAQ,GAAR,QAAQ,CAAY;IAC7B,CAAC;IAEJ,GAAG;QACC,OAAO,IAAI,CAAC,KAAK,CAAC;IACtB,CAAC;IACD,GAAG,CAAC,KAAQ;QACR,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC;QACpC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,OAAO;YAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;IACjC,CAAC;CACJ"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ Intended to hold values which must be determined by the view layer (ie. which depend on rendered layout)
3
+ and which affect other aspects of the UI.
4
+
5
+ Example: the UI renders an element, then checks if that element has overflow, then wants to toggle a class on that element in response to the check.
6
+
7
+ Your state machine / "data store" should own/create the WatchedMutableValue. It can pass it directly to the view layer, which is free to update it.
8
+ */
9
+ export class WatchedMutableValue<T> {
10
+ constructor(
11
+ private value: T,
12
+ private onchange: () => void,
13
+ ) {}
14
+
15
+ get() {
16
+ return this.value;
17
+ }
18
+ set(value: T) {
19
+ const changed = this.value != value;
20
+ this.value = value;
21
+ if (changed) this.onchange();
22
+ }
23
+ }
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "intermediate/*.ts",
8
8
  "README.md"
9
9
  ],
10
- "version": "1.3.1",
10
+ "version": "1.3.2",
11
11
  "description": "Work-in-progress",
12
12
  "main": "dist/index.js",
13
13
  "scripts": {