@swiftwc/ui 0.0.0-dev.95 → 0.0.0-dev.97
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/generated/client/index.js +7 -7
- package/generated/components/alert-dialog.d.ts +1 -1
- package/generated/components/alert-dialog.js +1 -1
- package/generated/components/content-unavailable.js +11 -11
- package/generated/components/date-picker.js +15 -15
- package/generated/components/fine-tooltip.d.ts +3 -0
- package/generated/components/fine-tooltip.js +5 -1
- package/generated/components/image-view.js +3 -2
- package/generated/components/label-view.d.ts +4 -0
- package/generated/components/label-view.js +11 -7
- package/generated/components/labeled-content.d.ts +5 -0
- package/generated/components/labeled-content.js +18 -12
- package/generated/components/menu-view.js +12 -12
- package/generated/components/navigation-title.js +2 -1
- package/generated/components/picker-view.d.ts +1 -1
- package/generated/components/picker-view.js +51 -50
- package/generated/components/progress-view.js +20 -19
- package/generated/components/scroll-view.js +14 -14
- package/generated/components/section-view.js +11 -11
- package/generated/components/table-view.js +34 -34
- package/generated/components/text-field.d.ts +2 -0
- package/generated/components/text-field.js +13 -11
- package/generated/components/toggle-view.js +30 -13
- package/generated/components/tool-bar.js +27 -27
- package/generated/css/index.css +67 -15
- package/generated/events/alert-dialog.d.ts +3 -0
- package/generated/events/confirmation-dialog.d.ts +3 -0
- package/generated/events/date-picker.d.ts +3 -0
- package/generated/events/lifecycle-observer.d.ts +4 -0
- package/generated/events/picker-view.d.ts +6 -0
- package/generated/events/scroll-view.d.ts +4 -0
- package/generated/events/tab-view.d.ts +10 -0
- package/generated/events/text-field.d.ts +3 -0
- package/generated/events/toggle-view.d.ts +3 -0
- package/generated/internal/utils/cash/index.d.ts +4 -3
- package/generated/internal/utils/cash/index.js +4 -2
- package/generated/internal/utils/ensure-placeholder.js +2 -1
- package/generated/morphdom/index.d.ts +4 -2
- package/generated/morphdom/index.js +4 -2
- package/generated/morphdom/morph.d.ts +2 -2
- package/generated/morphdom/morph.js +3 -2
- package/generated/morphdom/query-morph.d.ts +2 -2
- package/generated/morphdom/query-morph.js +1 -1
- package/generated/morphdom/render-to-string.d.ts +12 -0
- package/generated/morphdom/render-to-string.js +48 -0
- package/generated/morphdom/unsafe-html.d.ts +2 -0
- package/generated/morphdom/unsafe-html.js +4 -0
- package/generated/tpl/html.js +4 -0
- package/generated/tpl/index.d.ts +2 -0
- package/generated/tpl/index.js +2 -0
- package/generated/tpl/is-template-result.d.ts +3 -0
- package/generated/tpl/is-template-result.js +1 -0
- package/package.json +1 -1
- package/scss/_maps.scss +19 -13
- package/scss/base/_root.scss +1 -1
- package/scss/components/_picker-view.scss +7 -1
- package/scss/components/_scroll-view-toolbars.scss +8 -2
- package/scss/components/_toggle-view.scss +2 -1
- package/scss/mixins/_index.scss +8 -2
- package/scss/placeholders/_lists.scss +27 -1
- package/web-components.html-data/en.json +111 -128
- package/generated/morphdom/html.d.ts +0 -8
- package/generated/morphdom/html.js +0 -37
|
@@ -20,4 +20,10 @@ declare global {
|
|
|
20
20
|
'picker:searchblur': PickerSearchblurEvent;
|
|
21
21
|
'picker:searchinput': PickerSearchinputEvent;
|
|
22
22
|
}
|
|
23
|
+
interface DocumentEventMap {
|
|
24
|
+
selection: PickerSelectionEvent;
|
|
25
|
+
'picker:searchfocus': PickerSearchfocusEvent;
|
|
26
|
+
'picker:searchblur': PickerSearchblurEvent;
|
|
27
|
+
'picker:searchinput': PickerSearchinputEvent;
|
|
28
|
+
}
|
|
23
29
|
}
|
|
@@ -41,4 +41,14 @@ declare global {
|
|
|
41
41
|
'tab-view:toggle': TabViewToggleEvent;
|
|
42
42
|
'tab-view:adaptable-tab-bar-placement-change': TabViewAdaptableTabBarPlacementChangeEvent;
|
|
43
43
|
}
|
|
44
|
+
interface DocumentEventMap {
|
|
45
|
+
tabshow: TabshowEvent;
|
|
46
|
+
tabhide: TabhideEvent;
|
|
47
|
+
tabreveal: TabrevealEvent;
|
|
48
|
+
tabswap: TabswapEvent;
|
|
49
|
+
beforetabreveal: BeforetabrevealEvent;
|
|
50
|
+
beforetabswap: BeforetabswapEvent;
|
|
51
|
+
'tab-view:toggle': TabViewToggleEvent;
|
|
52
|
+
'tab-view:adaptable-tab-bar-placement-change': TabViewAdaptableTabBarPlacementChangeEvent;
|
|
53
|
+
}
|
|
44
54
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type TemplateResult } from '../../../tpl';
|
|
1
2
|
import ancestors from './ancestors';
|
|
2
3
|
import next from './next';
|
|
3
4
|
import nextAll from './next-all';
|
|
@@ -7,9 +8,9 @@ import prop from './prop';
|
|
|
7
8
|
import siblings from './siblings';
|
|
8
9
|
declare const DEFAULT: ">1";
|
|
9
10
|
interface CashFn {
|
|
10
|
-
(
|
|
11
|
-
<T extends Element = Element>(
|
|
12
|
-
<T extends Element = Element>(
|
|
11
|
+
(markup: TemplateResult): DocumentFragment;
|
|
12
|
+
<T extends Element = Element>(markup: TemplateResult, selector: typeof DEFAULT): T;
|
|
13
|
+
<T extends Element = Element>(markup: TemplateResult, selector: string): T;
|
|
13
14
|
prop: typeof prop;
|
|
14
15
|
nextAll: typeof nextAll;
|
|
15
16
|
prevAll: typeof prevAll;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { renderToString } from '../../../morphdom';
|
|
1
2
|
import ancestors from './ancestors';
|
|
2
3
|
import next from './next';
|
|
3
4
|
import nextAll from './next-all';
|
|
@@ -6,8 +7,9 @@ import prevAll from './prev-all';
|
|
|
6
7
|
import prop from './prop';
|
|
7
8
|
import siblings from './siblings';
|
|
8
9
|
const DEFAULT = '>1';
|
|
9
|
-
const cash = ((
|
|
10
|
-
|
|
10
|
+
const cash = ((markup, selector) => {
|
|
11
|
+
// NOTE: Use also runtime check isTemplateResult()??
|
|
12
|
+
const template = Object.assign(document.createElement('template'), { innerHTML: renderToString(markup).toString() });
|
|
11
13
|
if (!selector)
|
|
12
14
|
return template.content;
|
|
13
15
|
if (selector === DEFAULT)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
export { default as html } from './html';
|
|
2
|
-
export * from './html';
|
|
3
1
|
export { default as morph } from './morph';
|
|
4
2
|
export * from './morph';
|
|
5
3
|
export { default as queryMorph } from './query-morph';
|
|
6
4
|
export * from './query-morph';
|
|
5
|
+
export { default as renderToString } from './render-to-string';
|
|
6
|
+
export * from './render-to-string';
|
|
7
|
+
export { default as unsafeHtml } from './unsafe-html';
|
|
8
|
+
export * from './unsafe-html';
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
export { default as html } from './html';
|
|
2
|
-
export * from './html';
|
|
3
1
|
export { default as morph } from './morph';
|
|
4
2
|
export * from './morph';
|
|
5
3
|
export { default as queryMorph } from './query-morph';
|
|
6
4
|
export * from './query-morph';
|
|
5
|
+
export { default as renderToString } from './render-to-string';
|
|
6
|
+
export * from './render-to-string';
|
|
7
|
+
export { default as unsafeHtml } from './unsafe-html';
|
|
8
|
+
export * from './unsafe-html';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export default function (
|
|
1
|
+
import type { TemplateResult } from '../tpl';
|
|
2
|
+
export default function (markup: TemplateResult, fromEl?: Element, options?: {
|
|
3
3
|
cb: () => void;
|
|
4
4
|
}): void;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import morphdom from '../internal/vendor/morphdom';
|
|
2
|
-
|
|
2
|
+
import renderToString from './render-to-string';
|
|
3
|
+
export default function (markup, fromEl, options) {
|
|
3
4
|
if (!fromEl)
|
|
4
5
|
return;
|
|
5
|
-
morphdom(fromEl,
|
|
6
|
+
morphdom(fromEl, renderToString(markup).toString(), {
|
|
6
7
|
onBeforeElUpdated: (fromEl, toEl) => !fromEl.isEqualNode(toEl),
|
|
7
8
|
onBeforeElChildrenUpdated: (fromEl, toEl) => !toEl.matches('image-view,navigation-title'), // NOTE: image-view will alter it's contents! This is required to not empty it up again!
|
|
8
9
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export default function (scopedSelector: string, template:
|
|
1
|
+
import type { TemplateResult } from '../tpl';
|
|
2
|
+
export default function (scopedSelector: string, template: TemplateResult, container?: Element, options?: {
|
|
3
3
|
cb?: () => boolean;
|
|
4
4
|
removeIf?: boolean;
|
|
5
5
|
}): void;
|
|
@@ -5,7 +5,7 @@ export default function (scopedSelector, template, container, options) {
|
|
|
5
5
|
return;
|
|
6
6
|
if ('boolean' === typeof options?.removeIf && options?.removeIf)
|
|
7
7
|
return container?.querySelector(`:scope>${scopedSelector}`)?.remove();
|
|
8
|
-
const fromEl = container?.querySelector(`:scope>${scopedSelector}`) ?? container?.appendChild($(template
|
|
8
|
+
const fromEl = container?.querySelector(`:scope>${scopedSelector}`) ?? container?.appendChild($(template, '>1'));
|
|
9
9
|
if (!fromEl)
|
|
10
10
|
return;
|
|
11
11
|
morph(template, fromEl);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type TemplateResult } from '../tpl';
|
|
2
|
+
export declare class TrustedMarkup {
|
|
3
|
+
readonly value: string;
|
|
4
|
+
constructor(value: string);
|
|
5
|
+
toString(): string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Flatten a TemplateResult (from `html`) into an escaped TrustedMarkup
|
|
9
|
+
* string. Use this only at morph/queryMorph call sites — anywhere feeding
|
|
10
|
+
* `render()` should keep passing the raw TemplateResult straight through.
|
|
11
|
+
*/
|
|
12
|
+
export default function renderToString(template: TemplateResult): TrustedMarkup;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { isTemplateResult } from '../tpl';
|
|
2
|
+
// morph.ts and queryMorph.ts only need something with `.toString()` that
|
|
3
|
+
// yields a safe, escaped HTML string — this is that, built on top of the
|
|
4
|
+
// same TemplateResult instead of a separate tag function.
|
|
5
|
+
// values built via `raw` itself are trusted markup; wrap them so `stringify`
|
|
6
|
+
// knows to skip escaping — same idea as lit-html's `unsafeHTML`
|
|
7
|
+
export class TrustedMarkup {
|
|
8
|
+
value;
|
|
9
|
+
constructor(value) {
|
|
10
|
+
this.value = value;
|
|
11
|
+
}
|
|
12
|
+
toString() {
|
|
13
|
+
return this.value;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const ESCAPE_MAP = {
|
|
17
|
+
'&': '&',
|
|
18
|
+
'<': '<',
|
|
19
|
+
'>': '>',
|
|
20
|
+
'"': '"',
|
|
21
|
+
"'": ''',
|
|
22
|
+
};
|
|
23
|
+
function escapeHtml(str) {
|
|
24
|
+
return str.replace(/[&<>"']/g, (ch) => ESCAPE_MAP[ch]);
|
|
25
|
+
}
|
|
26
|
+
function stringifyValue(value) {
|
|
27
|
+
if (value === null || value === undefined || value === false)
|
|
28
|
+
return '';
|
|
29
|
+
if (value instanceof TrustedMarkup)
|
|
30
|
+
return value.value;
|
|
31
|
+
if (isTemplateResult(value))
|
|
32
|
+
return renderToString(value).value;
|
|
33
|
+
if (Array.isArray(value))
|
|
34
|
+
return value.map(stringifyValue).join('');
|
|
35
|
+
return escapeHtml(String(value));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Flatten a TemplateResult (from `html`) into an escaped TrustedMarkup
|
|
39
|
+
* string. Use this only at morph/queryMorph call sites — anywhere feeding
|
|
40
|
+
* `render()` should keep passing the raw TemplateResult straight through.
|
|
41
|
+
*/
|
|
42
|
+
export default function renderToString(template) {
|
|
43
|
+
let out = template.strings[0];
|
|
44
|
+
for (let i = 0; i < template.values.length; i++) {
|
|
45
|
+
out += stringifyValue(template.values[i]) + template.strings[i + 1];
|
|
46
|
+
}
|
|
47
|
+
return new TrustedMarkup(out.replace(/>\s+</g, '><').trim());
|
|
48
|
+
}
|
package/generated/tpl/html.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// Purely structural — captures strings/values as-is. render.ts relies on
|
|
2
|
+
// `strings` identity (TemplateStringsArray) for its template cache, so this
|
|
3
|
+
// must stay exactly this shape: no wrapping, no cloning, no new object
|
|
4
|
+
// allocation beyond the literal { strings, values }.
|
|
1
5
|
export default function (strings, ...values) {
|
|
2
6
|
return { strings, values };
|
|
3
7
|
}
|
package/generated/tpl/index.d.ts
CHANGED
package/generated/tpl/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default (v) => !!v && typeof v === 'object' && 'strings' in v && 'values' in v;
|
package/package.json
CHANGED
package/scss/_maps.scss
CHANGED
|
@@ -151,62 +151,67 @@ $block-placement-map: (
|
|
|
151
151
|
$label-fonts-map: (
|
|
152
152
|
footnote: (
|
|
153
153
|
size: 1rem,
|
|
154
|
-
|
|
154
|
+
leading: calc(1.1875 / 1),
|
|
155
155
|
weight: 400,
|
|
156
156
|
),
|
|
157
157
|
caption2: (
|
|
158
158
|
size: 0.75rem,
|
|
159
|
-
|
|
159
|
+
leading: calc(1.0625 / 0.75),
|
|
160
160
|
weight: 400,
|
|
161
161
|
),
|
|
162
162
|
caption: (
|
|
163
|
-
size: 0.
|
|
164
|
-
|
|
163
|
+
size: 0.8125rem,
|
|
164
|
+
leading: calc(1.25 / 0.8125),
|
|
165
165
|
weight: 400,
|
|
166
166
|
),
|
|
167
167
|
callout: (
|
|
168
168
|
size: 0.875rem,
|
|
169
|
-
|
|
169
|
+
leading: calc(1.1875 / 0.875),
|
|
170
170
|
weight: 400,
|
|
171
171
|
),
|
|
172
172
|
body: (
|
|
173
173
|
size: 1rem,
|
|
174
|
-
|
|
174
|
+
leading: calc(1.5 / 1),
|
|
175
175
|
weight: 400,
|
|
176
176
|
),
|
|
177
177
|
subheadline: (
|
|
178
178
|
size: 1.125rem,
|
|
179
|
-
|
|
179
|
+
leading: calc(1.6875 / 1.125),
|
|
180
180
|
weight: 400,
|
|
181
181
|
),
|
|
182
182
|
headline: (
|
|
183
183
|
size: 1.25rem,
|
|
184
|
-
|
|
184
|
+
leading: calc(1.75 / 1.25),
|
|
185
185
|
weight: 500,
|
|
186
186
|
),
|
|
187
187
|
title3: (
|
|
188
188
|
size: 1.5rem,
|
|
189
|
-
|
|
189
|
+
leading: calc(2 / 1.5),
|
|
190
190
|
weight: 600,
|
|
191
191
|
),
|
|
192
192
|
title2: (
|
|
193
193
|
size: 1.875rem,
|
|
194
|
-
|
|
194
|
+
leading: calc(2.25 / 1.875),
|
|
195
195
|
weight: 600,
|
|
196
196
|
),
|
|
197
197
|
title: (
|
|
198
198
|
size: 2.25rem,
|
|
199
|
-
|
|
199
|
+
leading: calc(2.5 / 2.25),
|
|
200
200
|
weight: 600,
|
|
201
201
|
),
|
|
202
202
|
large-title: (
|
|
203
203
|
size: 3rem,
|
|
204
|
-
|
|
204
|
+
leading: 1,
|
|
205
205
|
weight: 700,
|
|
206
206
|
),
|
|
207
207
|
extra-large-title: (
|
|
208
208
|
size: 3.75rem,
|
|
209
|
-
|
|
209
|
+
leading: 1,
|
|
210
|
+
weight: 700,
|
|
211
|
+
),
|
|
212
|
+
extra-large-title2: (
|
|
213
|
+
size: 4.5rem,
|
|
214
|
+
leading: 1,
|
|
210
215
|
weight: 700,
|
|
211
216
|
),
|
|
212
217
|
);
|
|
@@ -258,6 +263,7 @@ $button-sizes-map: (
|
|
|
258
263
|
$tint-names: gray, blue, red, green, orange, purple;
|
|
259
264
|
|
|
260
265
|
$foreground-tokens: (
|
|
266
|
+
primary: --primary,
|
|
261
267
|
secondary: --secondary,
|
|
262
268
|
blue: --blue,
|
|
263
269
|
red: --red,
|
package/scss/base/_root.scss
CHANGED
|
@@ -234,7 +234,7 @@
|
|
|
234
234
|
|
|
235
235
|
@each $label, $props in maps.$label-fonts-map {
|
|
236
236
|
--label-#{$label}-font-size: #{map.get($props, size)};
|
|
237
|
-
--label-#{$label}-line-height: #{map.get($props,
|
|
237
|
+
--label-#{$label}-line-height: #{map.get($props, leading)};
|
|
238
238
|
--label-#{$label}-font-weight: #{map.get($props, weight)};
|
|
239
239
|
}
|
|
240
240
|
|
|
@@ -152,13 +152,19 @@ $picker-ifs: (
|
|
|
152
152
|
&::part(picker-label-stack) {
|
|
153
153
|
display: var(--picker--labelstack-display, none); // display: none;
|
|
154
154
|
|
|
155
|
-
color: var(--secondary);
|
|
155
|
+
// color: var(--secondary);
|
|
156
156
|
|
|
157
157
|
--label-truncation-mode: tail;
|
|
158
158
|
|
|
159
159
|
--label-line-limit: 1;
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
form & {
|
|
163
|
+
:where(&)::part(picker-label-stack) {
|
|
164
|
+
color: var(--secondary);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
162
168
|
--picker--stack-grid-template-columns: minmax(30%, 1fr) auto;
|
|
163
169
|
|
|
164
170
|
--picker--stack-grid-template-rows: minmax(0, 1fr);
|
|
@@ -25,8 +25,14 @@
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
scroll-view:has(
|
|
29
|
-
|
|
28
|
+
scroll-view:has(
|
|
29
|
+
~ tool-bar > [slot^='top-bar'],
|
|
30
|
+
~ tool-bar > [slot='cancellation-action'],
|
|
31
|
+
~ tool-bar > [slot='primary-action'],
|
|
32
|
+
~ tool-bar > [slot='confirmation-action'],
|
|
33
|
+
~ tool-bar > [slot='destructive-action']
|
|
34
|
+
),
|
|
35
|
+
scroll-view:has(> [slot^='top-bar'], > [slot='cancellation-action'], > [slot='primary-action'], > [slot='confirmation-action'], > [slot='destructive-action']) {
|
|
30
36
|
:where(&)::part(scroll-view-navbar) {
|
|
31
37
|
visibility: visible;
|
|
32
38
|
}
|
package/scss/mixins/_index.scss
CHANGED
|
@@ -80,8 +80,14 @@
|
|
|
80
80
|
grid-area: main;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
&:has(
|
|
84
|
-
|
|
83
|
+
&:has(
|
|
84
|
+
~ tool-bar > [slot^='top-bar'],
|
|
85
|
+
~ tool-bar > [slot='cancellation-action'],
|
|
86
|
+
~ tool-bar > [slot='primary-action'],
|
|
87
|
+
~ tool-bar > [slot='confirmation-action'],
|
|
88
|
+
~ tool-bar > [slot='destructive-action']
|
|
89
|
+
),
|
|
90
|
+
&:has(> [slot^='top-bar'], > [slot='cancellation-action'], > [slot='primary-action'], > [slot='confirmation-action'], > [slot='destructive-action']) {
|
|
85
91
|
grid-template-rows: var(--navigation-bar-block-size) minmax(max-content, 1fr);
|
|
86
92
|
}
|
|
87
93
|
}
|
|
@@ -364,7 +364,7 @@ $list-item-selector: ':not([slot], section-view, [is="disclosure-group"], picker
|
|
|
364
364
|
}
|
|
365
365
|
|
|
366
366
|
&::part(section-header-stack) {
|
|
367
|
-
top:
|
|
367
|
+
top: var(--list--sticky-block-size, 0px); // + var(--navigation-bar-block-size));
|
|
368
368
|
|
|
369
369
|
position: sticky;
|
|
370
370
|
|
|
@@ -373,6 +373,32 @@ $list-item-selector: ':not([slot], section-view, [is="disclosure-group"], picker
|
|
|
373
373
|
// text-shadow: 0 0 5px var(--face);
|
|
374
374
|
}
|
|
375
375
|
}
|
|
376
|
+
|
|
377
|
+
// &:is([list-style*='inset'] section-view, [form-style*='inset'] section-view) {
|
|
378
|
+
// :where(&) {
|
|
379
|
+
// &::part(section-header-stack) {
|
|
380
|
+
// top: calc(var(--list--sticky-block-size, 0px) + 1rem);
|
|
381
|
+
// }
|
|
382
|
+
// }
|
|
383
|
+
// }
|
|
384
|
+
|
|
385
|
+
&:is(
|
|
386
|
+
scroll-view:has(
|
|
387
|
+
~ tool-bar > [slot^='top-bar'],
|
|
388
|
+
~ tool-bar > [slot='cancellation-action'],
|
|
389
|
+
~ tool-bar > [slot='primary-action'],
|
|
390
|
+
~ tool-bar > [slot='confirmation-action'],
|
|
391
|
+
~ tool-bar > [slot='destructive-action']
|
|
392
|
+
)
|
|
393
|
+
section-view,
|
|
394
|
+
scroll-view:has(> [slot^='top-bar'], > [slot='cancellation-action'], > [slot='primary-action'], > [slot='confirmation-action'], > [slot='destructive-action']) section-view
|
|
395
|
+
) {
|
|
396
|
+
:where(&) {
|
|
397
|
+
&::part(section-header-stack) {
|
|
398
|
+
top: calc(var(--list--sticky-block-size, 0px) + var(--navigation-bar-block-size));
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
376
402
|
}
|
|
377
403
|
|
|
378
404
|
// SECTION: Enable 2-col layout
|