@saltcorn/markup 0.6.2-beta.2 → 0.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.
Files changed (60) hide show
  1. package/dist/builder.d.ts +18 -0
  2. package/dist/builder.d.ts.map +1 -0
  3. package/dist/builder.js +57 -0
  4. package/dist/builder.js.map +1 -0
  5. package/dist/emergency_layout.d.ts +6 -0
  6. package/dist/emergency_layout.d.ts.map +1 -0
  7. package/dist/emergency_layout.js +38 -0
  8. package/dist/emergency_layout.js.map +1 -0
  9. package/dist/form.d.ts +12 -0
  10. package/dist/form.d.ts.map +1 -0
  11. package/dist/form.js +372 -0
  12. package/dist/form.js.map +1 -0
  13. package/dist/helpers.d.ts +58 -0
  14. package/dist/helpers.d.ts.map +1 -0
  15. package/dist/helpers.js +169 -0
  16. package/dist/helpers.js.map +1 -0
  17. package/dist/index.d.ts +21 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +158 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/layout.d.ts +22 -0
  22. package/dist/layout.d.ts.map +1 -0
  23. package/dist/layout.js +338 -0
  24. package/dist/layout.js.map +1 -0
  25. package/dist/layout_utils.d.ts +21 -0
  26. package/dist/layout_utils.d.ts.map +1 -0
  27. package/dist/layout_utils.js +272 -0
  28. package/dist/layout_utils.js.map +1 -0
  29. package/dist/mktag.d.ts +12 -0
  30. package/dist/mktag.d.ts.map +1 -0
  31. package/dist/mktag.js +100 -0
  32. package/dist/mktag.js.map +1 -0
  33. package/dist/table.d.ts +22 -0
  34. package/dist/table.d.ts.map +1 -0
  35. package/dist/table.js +51 -0
  36. package/dist/table.js.map +1 -0
  37. package/dist/tabs.d.ts +7 -0
  38. package/dist/tabs.d.ts.map +1 -0
  39. package/dist/tabs.js +34 -0
  40. package/dist/tabs.js.map +1 -0
  41. package/dist/tags.d.ts +17 -0
  42. package/dist/tags.d.ts.map +1 -0
  43. package/dist/tags.js +71 -0
  44. package/dist/tags.js.map +1 -0
  45. package/dist/tsconfig.ref.tsbuildinfo +1 -0
  46. package/package.json +25 -6
  47. package/builder.js +0 -101
  48. package/emergency_layout.js +0 -54
  49. package/form.js +0 -603
  50. package/form.test.js +0 -98
  51. package/helpers.js +0 -268
  52. package/index.js +0 -226
  53. package/layout.js +0 -590
  54. package/layout.test.js +0 -39
  55. package/layout_utils.js +0 -394
  56. package/markup.test.js +0 -104
  57. package/mktag.js +0 -105
  58. package/table.js +0 -115
  59. package/tabs.js +0 -54
  60. package/tags.js +0 -56
package/layout.js DELETED
@@ -1,590 +0,0 @@
1
- /**
2
- * @category saltcorn-markup
3
- * @module layout
4
- */
5
-
6
- const { contract, is } = require("contractis");
7
- const {
8
- div,
9
- a,
10
- span,
11
- text,
12
- img,
13
- p,
14
- h1,
15
- h2,
16
- h3,
17
- h4,
18
- h5,
19
- h6,
20
- label,
21
- ul,
22
- button,
23
- li,
24
- i,
25
- genericElement,
26
- } = require("./tags");
27
- const { alert, breadcrumbs } = require("./layout_utils");
28
- const { search_bar_form, search_bar } = require("./helpers");
29
-
30
- /**
31
- * @param {object[]} [alerts]
32
- * @returns {boolean}
33
- */
34
- const couldHaveAlerts = (alerts) => alerts || Array.isArray(alerts);
35
-
36
- /**
37
- * @param {string|object} body
38
- * @param {object[]} [alerts]
39
- * @returns {object}
40
- */
41
- const makeSegments = (body, alerts) => {
42
- const alertsSegments = couldHaveAlerts(alerts)
43
- ? [
44
- {
45
- type: "blank",
46
- contents: div(
47
- { id: "alerts-area" },
48
- (alerts || []).map((a) => alert(a.type, a.msg))
49
- ),
50
- },
51
- ]
52
- : [];
53
-
54
- if (typeof body === "string")
55
- return {
56
- above: [...alertsSegments, { type: "blank", contents: body }],
57
- };
58
- else if (body.above) {
59
- if (couldHaveAlerts(alerts)) body.above.unshift(alertsSegments[0]);
60
- return body;
61
- } else return { above: [...alertsSegments, body] };
62
- };
63
-
64
- /**
65
- *
66
- * @param {object} segment
67
- * @param {string} inner
68
- * @returns {div|span|string}
69
- */
70
- const applyTextStyle = (segment, inner) => {
71
- let style = segment.font ? { fontFamily: segment.font } : {};
72
- switch (segment.textStyle) {
73
- case "h1":
74
- return h1(style, inner);
75
- case "h2":
76
- return h2(style, inner);
77
- case "h3":
78
- return h3(style, inner);
79
- case "h4":
80
- return h4(style, inner);
81
- case "h5":
82
- return h5(style, inner);
83
- case "h6":
84
- return h6(style, inner);
85
- default:
86
- return segment.block
87
- ? div({ class: segment.textStyle || "", style }, inner)
88
- : segment.textStyle || segment.font
89
- ? span({ class: segment.textStyle || "", style }, inner)
90
- : inner;
91
- }
92
- };
93
-
94
- /**
95
- * @param {object} opts
96
- * @param {object[]} opts.contents
97
- * @param {string[]} opts.titles
98
- * @param {string} opts.tabsStyle
99
- * @param {*} opts.ntabs
100
- * @param {function} go
101
- * @returns {ul_div}
102
- */
103
- const renderTabs = (
104
- { contents, titles, tabsStyle, ntabs, independent },
105
- go
106
- ) => {
107
- const rndid = `tab${Math.floor(Math.random() * 16777215).toString(16)}`;
108
- if (tabsStyle === "Accordion")
109
- return div(
110
- { class: "accordion", id: `${rndid}top` },
111
- contents.map((t, ix) =>
112
- div(
113
- { class: "card" },
114
- div(
115
- { class: "card-header", id: `${rndid}head${ix}` },
116
- h2(
117
- { class: "mb-0" },
118
- button(
119
- {
120
- class: "btn btn-link btn-block text-left",
121
- type: "button",
122
- "data-toggle": "collapse",
123
- "data-target": `#${rndid}tab${ix}`,
124
- "aria-expanded": ix === 0 ? "true" : "false",
125
- "aria-controls": `${rndid}tab${ix}`,
126
- },
127
- titles[ix]
128
- )
129
- )
130
- ),
131
- div(
132
- {
133
- class: ["collapse", ix === 0 && "show"],
134
- id: `${rndid}tab${ix}`,
135
- "aria-labelledby": `${rndid}head${ix}`,
136
- "data-parent": independent ? undefined : `#${rndid}top`,
137
- },
138
- div({ class: "card-body" }, go(t, false, ix))
139
- )
140
- )
141
- )
142
- );
143
- else
144
- return (
145
- ul(
146
- {
147
- role: "tablist",
148
- id: `${rndid}`,
149
- class: `nav ${tabsStyle === "Tabs" ? "nav-tabs" : "nav-pills"}`,
150
- },
151
- contents.map((t, ix) =>
152
- li(
153
- { class: "nav-item", role: "presentation" },
154
- a(
155
- {
156
- class: ["nav-link", ix === 0 && "active"],
157
- id: `${rndid}link${ix}`,
158
- "data-toggle": "tab",
159
- href: `#${rndid}tab${ix}`,
160
- role: "tab",
161
- "aria-controls": `${rndid}tab${ix}`,
162
- "aria-selected": ix === 0 ? "true" : "false",
163
- },
164
- titles[ix]
165
- )
166
- )
167
- )
168
- ) +
169
- div(
170
- { class: "tab-content", id: `${rndid}content` },
171
- contents.map((t, ix) =>
172
- div(
173
- {
174
- class: ["tab-pane fade", ix === 0 && "show active"],
175
- role: "tabpanel",
176
- id: `${rndid}tab${ix}`,
177
- "aria-labelledby": `${rndid}link${ix}`,
178
- },
179
- go(t, false, ix)
180
- )
181
- )
182
- )
183
- );
184
- };
185
-
186
- /**
187
- * @param {object} opts
188
- * @param {object} opts.blockDispatch
189
- * @param {object|string} opts.layout
190
- * @param {object} [opts.role]
191
- * @param {object[]} [opts.alerts]
192
- * @param {boolean} opts.is_owner missing in contract
193
- * @returns {string}
194
- */
195
- const render = ({ blockDispatch, layout, role, alerts, is_owner }) => {
196
- //console.log(JSON.stringify(layout, null, 2));
197
- function wrap(segment, isTop, ix, inner) {
198
- const iconTag = segment.icon ? i({ class: segment.icon }) + " " : "";
199
- if (isTop && blockDispatch && blockDispatch.wrapTop)
200
- return blockDispatch.wrapTop(segment, ix, inner);
201
- else
202
- return segment.labelFor
203
- ? label(
204
- { for: `input${text(segment.labelFor)}` },
205
- applyTextStyle(segment, iconTag + inner)
206
- )
207
- : applyTextStyle(segment, iconTag + inner);
208
- }
209
- function go(segment, isTop, ix) {
210
- if (!segment) return "";
211
- if (
212
- typeof segment === "object" &&
213
- Object.keys(segment).length === 0 &&
214
- segment.constructor === Object
215
- )
216
- return "";
217
- if (typeof segment === "string") return wrap(segment, isTop, ix, segment);
218
- if (Array.isArray(segment))
219
- return wrap(
220
- segment,
221
- isTop,
222
- ix,
223
- segment.map((s, jx) => go(s, isTop, jx + ix)).join("")
224
- );
225
- if (segment.minRole && role > segment.minRole) return "";
226
- if (segment.type && blockDispatch && blockDispatch[segment.type]) {
227
- return wrap(segment, isTop, ix, blockDispatch[segment.type](segment, go));
228
- }
229
- if (segment.type === "blank") {
230
- return wrap(segment, isTop, ix, segment.contents || "");
231
- }
232
- if (segment.type === "breadcrumbs") {
233
- return wrap(segment, isTop, ix, breadcrumbs(segment.crumbs || []));
234
- }
235
- if (segment.type === "view") {
236
- return wrap(segment, isTop, ix, segment.contents || "");
237
- }
238
- if (segment.type === "pageHeader") {
239
- return wrap(
240
- segment,
241
- isTop,
242
- ix,
243
- h1(segment.title) + p(segment.blurb || "")
244
- );
245
- }
246
- if (segment.type === "image") {
247
- const srctype = segment.srctype || "File";
248
- return wrap(
249
- segment,
250
- isTop,
251
- ix,
252
- img({
253
- class: "w-100",
254
- alt: segment.alt,
255
- src:
256
- srctype === "File" ? `/files/serve/${segment.fileid}` : segment.url,
257
- })
258
- );
259
- }
260
- if (segment.type === "link") {
261
- let style =
262
- segment.link_style === "btn btn-custom-color"
263
- ? `background-color: ${
264
- segment.link_bgcol || "#000000"
265
- };border-color: ${segment.link_bordercol || "#000000"}; color: ${
266
- segment.link_textcol || "#000000"
267
- }`
268
- : null;
269
- return wrap(
270
- segment,
271
- isTop,
272
- ix,
273
- a(
274
- {
275
- href: segment.url,
276
- class: [segment.link_style || "", segment.link_size || ""],
277
- target: segment.target_blank ? "_blank" : false,
278
- rel: segment.nofollow ? "nofollow" : false,
279
- style,
280
- },
281
- segment.link_icon ? i({ class: segment.link_icon }) + " " : "",
282
- segment.text
283
- )
284
- );
285
- }
286
- if (segment.type === "card")
287
- return wrap(
288
- segment,
289
- isTop,
290
- ix,
291
- div(
292
- {
293
- class: [
294
- "card mt-4",
295
- segment.shadow === false ? false : "shadow",
296
- segment.class,
297
- segment.url && "with-link",
298
- ],
299
- onclick: segment.url ? `location.href='${segment.url}'` : false,
300
- style: segment.style,
301
- },
302
- segment.title &&
303
- div(
304
- { class: "card-header" },
305
- typeof segment.title === "string"
306
- ? h6(
307
- { class: "m-0 font-weight-bold text-primary" },
308
- segment.title
309
- )
310
- : segment.title
311
- ),
312
- segment.tabContents &&
313
- div(
314
- { class: "card-header" },
315
- ul(
316
- { class: "nav nav-tabs card-header-tabs" },
317
- Object.keys(segment.tabContents).map((title, ix) =>
318
- li(
319
- { class: "nav-item" },
320
- a(
321
- {
322
- class: ["nav-link", ix === 0 && "active"],
323
- href: `#tab-${title}`,
324
- "data-toggle": "tab",
325
- role: "tab",
326
- },
327
- title
328
- )
329
- )
330
- )
331
- )
332
- ) +
333
- div(
334
- {
335
- class: [
336
- "card-body",
337
- segment.bodyClass,
338
- segment.noPadding && "p-0",
339
- ],
340
- },
341
- div(
342
- { class: "tab-content", id: "myTabContent" },
343
- Object.entries(segment.tabContents).map(
344
- ([title, contents], ix) =>
345
- div(
346
- {
347
- class: ["tab-pane", ix == 0 && "show active"],
348
- id: `tab-${title}`,
349
- },
350
- contents
351
- )
352
- )
353
- )
354
- ),
355
- segment.contents &&
356
- div(
357
- {
358
- class: [
359
- "card-body",
360
- segment.bodyClass,
361
- segment.noPadding && "p-0",
362
- ],
363
- },
364
- go(segment.contents)
365
- ),
366
- segment.footer && div({ class: "card-footer" }, go(segment.footer))
367
- )
368
- );
369
- if (segment.type === "tabs")
370
- return wrap(segment, isTop, ix, renderTabs(segment, go));
371
- if (segment.type === "container") {
372
- const {
373
- bgFileId,
374
- bgType,
375
- bgColor,
376
- vAlign,
377
- hAlign,
378
- block,
379
- display,
380
- imageSize,
381
- borderWidth,
382
- borderStyle,
383
- setTextColor,
384
- textColor,
385
- showForRole,
386
- hide,
387
- customClass,
388
- customCSS,
389
- minScreenWidth,
390
- maxScreenWidth,
391
- showIfFormulaInputs,
392
- show_for_owner,
393
- borderDirection,
394
- borderRadius,
395
- borderRadiusUnit,
396
- borderColor,
397
- url,
398
- hoverColor,
399
- gradStartColor,
400
- gradEndColor,
401
- gradDirection,
402
- fullPageWidth,
403
- overflow,
404
- rotate,
405
- style,
406
- htmlElement,
407
- } = segment;
408
- if (hide) return "";
409
- if (
410
- showForRole &&
411
- showForRole[role] === false &&
412
- !(show_for_owner && is_owner)
413
- )
414
- return "";
415
- const renderBg = true;
416
- const sizeProp = (segKey, cssNm, unit) =>
417
- typeof segment[segKey] === "undefined"
418
- ? ""
419
- : `${cssNm}: ${segment[segKey]}${
420
- unit || segment[segKey + "Unit"] || "px"
421
- };`;
422
- const ppCustomCSS = (s) => (s ? s.split("\n").join("") + ";" : "");
423
- const baseDisplayClass =
424
- block === false ? "inline-block" : display ? display : "block";
425
- let displayClass = minScreenWidth
426
- ? `d-none d-${minScreenWidth}-${baseDisplayClass}`
427
- : baseDisplayClass === "block"
428
- ? false // no need
429
- : `d-${baseDisplayClass}`;
430
- if (maxScreenWidth)
431
- displayClass = `${displayClass} d-${maxScreenWidth}-none`;
432
- const allZero = (xs) => xs.every((x) => +x === 0);
433
- const ppBox = (what) =>
434
- !segment[what] || allZero(segment[what])
435
- ? ""
436
- : `${what}: ${segment[what].map((p) => p + "px").join(" ")};`;
437
- let flexStyles = "";
438
- Object.keys(style || {}).forEach((k) => {
439
- flexStyles += `${k}:${style[k]};`;
440
- });
441
- return wrap(
442
- segment,
443
- isTop,
444
- ix,
445
- genericElement(
446
- htmlElement || "div",
447
- {
448
- class: [
449
- customClass || false,
450
- hAlign && `text-${hAlign}`,
451
- vAlign === "middle" && "d-flex align-items-center",
452
- vAlign === "bottom" && "d-flex align-items-end",
453
- vAlign === "middle" &&
454
- hAlign === "center" &&
455
- "justify-content-center",
456
- displayClass,
457
- url && "with-link",
458
- hoverColor && `hover-${hoverColor}`,
459
- fullPageWidth && "full-page-width",
460
- ],
461
- onclick: segment.url ? `location.href='${segment.url}'` : false,
462
-
463
- style: `${flexStyles}${ppCustomCSS(customCSS || "")}${sizeProp(
464
- "minHeight",
465
- "min-height"
466
- )}${sizeProp("height", "height")}${sizeProp(
467
- "width",
468
- "width"
469
- )}${sizeProp("widthPct", "width", "%")}border${
470
- borderDirection ? `-${borderDirection}` : ""
471
- }: ${borderWidth || 0}px ${borderStyle} ${
472
- borderColor || "black"
473
- };${sizeProp("borderRadius", "border-radius")}${ppBox(
474
- "padding"
475
- )}${ppBox("margin")}${
476
- overflow && overflow !== "visible"
477
- ? ` overflow: ${overflow};`
478
- : ""
479
- } ${
480
- renderBg && bgType === "Image" && bgFileId && +bgFileId
481
- ? `background-image: url('/files/serve/${bgFileId}'); background-size: ${
482
- imageSize === "repeat" ? "auto" : imageSize || "contain"
483
- }; background-repeat: ${
484
- imageSize === "repeat" ? "repeat" : "no-repeat"
485
- };`
486
- : ""
487
- } ${
488
- renderBg && bgType === "Color"
489
- ? `background-color: ${bgColor};`
490
- : ""
491
- } ${
492
- renderBg && bgType === "Gradient"
493
- ? `background-image: linear-gradient(${
494
- gradDirection || 0
495
- }deg, ${gradStartColor}, ${gradEndColor});`
496
- : ""
497
- } ${setTextColor ? `color: ${textColor};` : ""}${
498
- rotate ? `transform: rotate(${rotate}deg);` : ""
499
- }`,
500
- ...(showIfFormulaInputs
501
- ? {
502
- "data-show-if": `showIfFormulaInputs(e, '${showIfFormulaInputs}')`,
503
- }
504
- : {}),
505
- },
506
- renderBg &&
507
- bgType === "Image" &&
508
- bgFileId &&
509
- +bgFileId &&
510
- div(
511
- { style: "display:none" },
512
- img({
513
- height: "1",
514
- width: "1",
515
- alt: "",
516
- src: `/files/serve/${bgFileId}`,
517
- })
518
- ),
519
- go(segment.contents)
520
- )
521
- );
522
- }
523
-
524
- if (segment.type === "line_break") {
525
- return "<br />";
526
- }
527
- if (segment.type === "search_bar") {
528
- return `<form action="/search" method="get">${search_bar("q", "", {
529
- has_dropdown: segment.has_dropdown,
530
- contents: go(segment.contents),
531
- })}</form>`;
532
- }
533
- if (segment.above) {
534
- return segment.above.map((s, ix) => go(s, isTop, ix)).join("");
535
- } else if (segment.besides) {
536
- const defwidth = Math.round(12 / segment.besides.length);
537
- const cardDeck =
538
- segment.besides.every((s) => s && s.type === "card") &&
539
- (!segment.widths || segment.widths.every((w) => w === defwidth));
540
- let markup;
541
- if (cardDeck)
542
- markup = div(
543
- { class: "card-deck" },
544
- segment.besides.map((t, ixb) => go(t, false, ixb))
545
- );
546
- else
547
- markup = div(
548
- { class: "row w-100" },
549
- segment.besides.map((t, ixb) =>
550
- div(
551
- {
552
- class:
553
- segment.widths === false
554
- ? ""
555
- : `col-${
556
- segment.breakpoint
557
- ? segment.breakpoint + "-"
558
- : segment.breakpoints && segment.breakpoints[ixb]
559
- ? segment.breakpoints[ixb] + "-"
560
- : ""
561
- }${segment.widths ? segment.widths[ixb] : defwidth}${
562
- segment.aligns ? " text-" + segment.aligns[ixb] : ""
563
- }`,
564
- },
565
- go(t, false, ixb)
566
- )
567
- )
568
- );
569
- return isTop ? wrap(segment, isTop, ix, markup) : markup;
570
- } else throw new Error("unknown layout segment" + JSON.stringify(segment));
571
- }
572
- return go(makeSegments(layout, alerts), true, 0);
573
- };
574
-
575
- const is_segment = is.obj({ type: is.maybe(is.str) });
576
-
577
- module.exports = contract(
578
- is.fun(
579
- is.obj({
580
- blockDispatch: is.maybe(is.objVals(is.fun(is_segment, is.str))),
581
- layout: is.or(is_segment, is.str),
582
- role: is.maybe(is.posint),
583
- alerts: is.maybe(
584
- is.array(is.obj({ type: is.str, msg: is.or(is.str, is.array(is.str)) }))
585
- ),
586
- }),
587
- is.str
588
- ),
589
- render
590
- );
package/layout.test.js DELETED
@@ -1,39 +0,0 @@
1
- const render = require("./layout");
2
- const { p } = require("./tags");
3
-
4
- describe("layout", () => {
5
- it("renders a simple layout", () => {
6
- const blockDispatch = {
7
- wrapTop(segment, ix, s) {
8
- return p(s);
9
- },
10
- reverseIt({ theString }) {
11
- return theString.split("").reverse().join("");
12
- },
13
- };
14
- const markup = { above: [{ type: "reverseIt", theString: "foobar" }] };
15
- expect(render({ blockDispatch, layout: markup })).toBe("<p>raboof</p>");
16
- });
17
- it("renders a nested layout", () => {
18
- const blockDispatch = {};
19
- const markup = {
20
- above: [
21
- {
22
- besides: [
23
- { type: "blank", contents: "hello" },
24
- { type: "blank", contents: "world" },
25
- ],
26
- },
27
- {
28
- besides: [
29
- { type: "blank", contents: "bar" },
30
- { type: "blank", contents: "foo" },
31
- ],
32
- },
33
- ],
34
- };
35
- expect(render({ blockDispatch, layout: markup })).toBe(
36
- '<div class="row w-100"><div class="col-6">hello</div><div class="col-6">world</div></div><div class="row w-100"><div class="col-6">bar</div><div class="col-6">foo</div></div>'
37
- );
38
- });
39
- });