@terra-symposium/docs 0.1.78 → 0.1.80
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/lib-dist/components/StaticWorkspace.d.ts +11 -1
- package/lib-dist/components/StaticWorkspace.d.ts.map +1 -1
- package/lib-dist/components/StaticWorkspace.js +163 -52
- package/lib-dist/components/StaticWorkspace.js.map +1 -1
- package/lib-dist/components/terra/pages/docs/_sidebar.d.ts +8 -18
- package/lib-dist/components/terra/pages/docs/_sidebar.d.ts.map +1 -1
- package/lib-dist/components/terra/pages/docs/_sidebar.js +199 -136
- package/lib-dist/components/terra/pages/docs/_sidebar.js.map +1 -1
- package/lib-dist/components/terra/pages/docs/_toolbar.d.ts +2 -4
- package/lib-dist/components/terra/pages/docs/_toolbar.d.ts.map +1 -1
- package/lib-dist/components/terra/pages/docs/_toolbar.js +85 -66
- package/lib-dist/components/terra/pages/docs/_toolbar.js.map +1 -1
- package/lib-dist/components/terra/ui.d.ts +42 -11
- package/lib-dist/components/terra/ui.d.ts.map +1 -1
- package/lib-dist/components/terra/ui.js +55 -14
- package/lib-dist/components/terra/ui.js.map +1 -1
- package/lib-dist/lib/astro.d.ts +1 -0
- package/lib-dist/lib/astro.d.ts.map +1 -1
- package/lib-dist/lib/astro.js +1 -0
- package/lib-dist/lib/astro.js.map +1 -1
- package/lib-dist/style.css +1 -1
- package/package.json +2 -2
- package/site/astro.config.mjs +84 -1
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* src/components/terra/pages/docs/_toolbar.tsx
|
|
4
|
+
*/
|
|
2
5
|
// @ts-nocheck -- source-preserving extraction; public host contracts are typed in src/host.ts.
|
|
3
6
|
/**
|
|
4
7
|
* astro/src/pages/docs/_toolbar.tsx
|
|
@@ -9,41 +12,31 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
9
12
|
IMPORTS
|
|
10
13
|
//////////////////////////////////////////////////*/
|
|
11
14
|
// API
|
|
12
|
-
import { clearTransition, setTransition, useAtom } from '../../../../lib/terra/docs/state.js';
|
|
13
15
|
import { $attachmentFilter } from '../../../../lib/terra/docs/attachments.js';
|
|
14
|
-
import { codeViewOf } from '../../../../lib/terra/docs/editor-dom.js';
|
|
15
|
-
import { FindReplace } from './_toolbar-find-replace.js';
|
|
16
|
-
import { toolbarFocusValue } from '../../../../lib/terra/docs/toolbar.js';
|
|
17
|
-
import { isDocBody } from '../../../../lib/terra/runtime/types.js';
|
|
18
16
|
import { $createHeadingNode } from '@lexical/rich-text';
|
|
19
17
|
import { $createParagraphNode, $getNearestNodeFromDOMNode, $isElementNode } from 'lexical';
|
|
20
18
|
import { actions } from '../../../../lib/terra/runtime/action-proxy.js';
|
|
21
|
-
import {
|
|
19
|
+
import { clearTransition, setTransition, useAtom } from '../../../../lib/terra/docs/state.js';
|
|
22
20
|
import { cn, notify } from '../../../../lib/terra/runtime/runtime.js';
|
|
21
|
+
import { codeViewOf } from '../../../../lib/terra/docs/editor-dom.js';
|
|
23
22
|
import { components as repoComponents } from '../../../../lib/terra/custom-components.js';
|
|
23
|
+
import { dirname, docsRootPath, toPascal } from '../../../../lib/terra/runtime/shared.js';
|
|
24
|
+
import { getDocsHostAdapter } from '../../../../lib/host-runtime.js';
|
|
25
|
+
import { isDocBody } from '../../../../lib/terra/runtime/types.js';
|
|
24
26
|
import { redo, redoDepth, undo, undoDepth } from '@codemirror/commands';
|
|
25
27
|
import { stringifyDocBody } from '../../../../lib/terra/runtime/content/document-markdown.js';
|
|
26
28
|
import { toast } from 'sonner';
|
|
29
|
+
import { toolbarFocusValue } from '../../../../lib/terra/docs/toolbar.js';
|
|
27
30
|
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
28
|
-
import { getDocsHostAdapter } from '../../../../lib/host-runtime.js';
|
|
29
31
|
// COMPONENTS
|
|
30
32
|
import * as TerraQualityRegex from '../../../../lib/terra/regex.mjs';
|
|
31
33
|
import React from 'react';
|
|
32
|
-
import { TextTooltip, TooltipProvider } from '@terra-symposium/styling/ui';
|
|
33
34
|
import { ArrowUpRight as PopOutIcon, CaretDown as CaretDownIcon, DataShare as ShareIcon, Image as ImageIcon, Link as LinkIcon, ListBulleted as BulletListIcon, ListNumbered as NumberListIcon, Paste as PasteIcon, Redo as RedoIcon, RepoSourceCode as ModuleIcon, Search as SearchIcon, Task as CheckListIcon, TextBold as BoldIcon, TextFont as TextFontIcon, TextItalic as ItalicIcon, TextStrikethrough as StrikethroughIcon, TextUnderline as UnderlineIcon, Undo as UndoIcon, } from '@carbon/icons-react';
|
|
34
|
-
import { Button as UiButton } from '@terra-symposium/styling/ui';
|
|
35
|
-
import { ButtonGroup } from '@terra-symposium/styling/ui';
|
|
35
|
+
import { Button as UiButton, ButtonGroup, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Input, Label, Popover, PopoverContent, PopoverTrigger, SearchEmpty, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, TextTooltip, ToggleGroup, ToggleGroupItem, TooltipProvider, } from '@terra-symposium/styling/ui';
|
|
36
36
|
import { CodeBlock } from '../../editor/docs/_CodeBlock.js';
|
|
37
|
-
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@terra-symposium/styling/ui';
|
|
38
|
-
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from '@terra-symposium/styling/ui';
|
|
39
37
|
import { EditStateCtx } from '../../../../lib/terra/docs/state.js';
|
|
40
38
|
import { ErrorBoundary } from '../../ui.js';
|
|
41
|
-
import {
|
|
42
|
-
import { Label } from '@terra-symposium/styling/ui';
|
|
43
|
-
import { Popover, PopoverContent, PopoverTrigger } from '@terra-symposium/styling/ui';
|
|
44
|
-
import { SearchEmpty } from '@terra-symposium/styling/ui';
|
|
45
|
-
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, } from '@terra-symposium/styling/ui';
|
|
46
|
-
import { ToggleGroup, ToggleGroupItem } from '@terra-symposium/styling/ui';
|
|
39
|
+
import { FindReplace } from './_toolbar-find-replace.js';
|
|
47
40
|
// DATA
|
|
48
41
|
import { ATTCH_TYPES } from '../../../../lib/terra/docs/attachments.js';
|
|
49
42
|
import { DOCS_BLOCK_ICONS } from './_icons.js';
|
|
@@ -68,11 +61,13 @@ const MENU_WIDTH_CLASS = 'w-56';
|
|
|
68
61
|
HELPERS
|
|
69
62
|
//////////////////////////////////////////////////*/
|
|
70
63
|
/**
|
|
71
|
-
*
|
|
64
|
+
* Measures the visible text offset of a DOM position within the active editor.
|
|
72
65
|
*
|
|
73
|
-
* @param content
|
|
74
|
-
* @param node
|
|
75
|
-
* @param
|
|
66
|
+
* @param content Editor element whose rendered text supplies the offset basis.
|
|
67
|
+
* @param node DOM node containing the position being measured.
|
|
68
|
+
* @param val Offset within `node` at which the range should end.
|
|
69
|
+
*
|
|
70
|
+
* @return Character count before the position, or the full editor text length when the node is outside it.
|
|
76
71
|
*/
|
|
77
72
|
const codeOffset = (content, node, val) => {
|
|
78
73
|
if (!content.contains(node))
|
|
@@ -82,14 +77,6 @@ const codeOffset = (content, node, val) => {
|
|
|
82
77
|
range.setEnd(node, val);
|
|
83
78
|
return range.toString().length;
|
|
84
79
|
};
|
|
85
|
-
/**
|
|
86
|
-
* Derives a clean, human-readable label from a raw filename or URL.
|
|
87
|
-
*
|
|
88
|
-
* @param {string} v - The raw filename or path string.
|
|
89
|
-
* @param {string} fallback - The default label if extraction fails.
|
|
90
|
-
*
|
|
91
|
-
* @return {string} The formatted, capitalized label.
|
|
92
|
-
*/
|
|
93
80
|
/**
|
|
94
81
|
* Prevents the active selection range from being lost when clicking toolbar buttons.
|
|
95
82
|
*
|
|
@@ -152,12 +139,18 @@ function looksLikeJsonBlob(val) {
|
|
|
152
139
|
// prettier-ignore
|
|
153
140
|
return ['{}', '[]'].some(p => v.startsWith(p[0]) && v.endsWith(p[1])) && v.length > 80;
|
|
154
141
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
142
|
+
const Button = React.forwardRef(
|
|
143
|
+
/**
|
|
144
|
+
* Renders the toolbar's compact button with its label and optional shortcut hint.
|
|
145
|
+
*
|
|
146
|
+
* @param props Button content, label, shortcut, active state, and native button attributes.
|
|
147
|
+
* @param ref Forwarded reference attached to the rendered button.
|
|
148
|
+
* @returns The styled button wrapped in its tooltip.
|
|
149
|
+
*/
|
|
150
|
+
function Button(props, ref) {
|
|
151
|
+
const { children: c, className: v, disabled: d, lbl: l, shortcut: s, onClick: o, onMouseDown: r, active: a, ...p } = props;
|
|
159
152
|
void a;
|
|
160
|
-
return (_jsx(TextTooltip, { content: s ? `${l} (${s})` : l, side: "top", align: "center", delayDuration: 400, children: _jsx(UiButton, { ref:
|
|
153
|
+
return (_jsx(TextTooltip, { content: s ? `${l} (${s})` : l, side: "top", align: "center", delayDuration: 400, children: _jsx(UiButton, { ref: ref, variant: "ghost", size: "xs", "aria-label": l, disabled: d, onClick: o, onMouseDown: r, className: cn('inline-flex h-6 !p-0.5 shadow-none', v), ...p, children: c }) }));
|
|
161
154
|
});
|
|
162
155
|
Button.displayName = 'Button';
|
|
163
156
|
/**
|
|
@@ -181,18 +174,15 @@ function Mode({ mode, onModeChange, disabled, editable, size = 'xs', }) {
|
|
|
181
174
|
onModeChange(n);
|
|
182
175
|
}, children: [_jsx(SelectTrigger, { "aria-label": "Mode", width: "fit", children: _jsx(SelectValue, { placeholder: "Mode" }) }), _jsx(SelectContent, { align: 'start', children: (editable ? ['view', 'edit', 'attachments'] : ['view', 'attachments']).map(o => _jsx(SelectItem, { value: o, children: o[0].toUpperCase() + o.slice(1) }, o)) })] }));
|
|
183
176
|
}
|
|
184
|
-
/**
|
|
185
|
-
* Renders Docs-specific controls beside a content editor toolbar.
|
|
186
|
-
*
|
|
187
|
-
* Formatting and content insertion remain editor-owned; these controls manage
|
|
188
|
-
* the document shell's mode and persistence state.
|
|
189
|
-
*
|
|
190
|
-
* @param props - Docs toolbar state and current mode.
|
|
191
|
-
*
|
|
192
|
-
* @return The mode, history, save, or version actions supported by the active Docs editor toolbar.
|
|
193
|
-
*/
|
|
194
177
|
const TOOLBAR_COMPONENTS = {
|
|
195
|
-
|
|
178
|
+
/**
|
|
179
|
+
* Adds Docs-specific mode, history, save, and version controls beside an editor toolbar.
|
|
180
|
+
*
|
|
181
|
+
* @param props Active mode, editability, control size, and toolbar state.
|
|
182
|
+
*
|
|
183
|
+
* @return Supported Docs actions, or `null` when the host is read-only.
|
|
184
|
+
*/
|
|
185
|
+
DocsToolbarActions({ activeMode: aMode, editable, size = 'xs', toolbar, }) {
|
|
196
186
|
const edit = useContext(EditStateCtx);
|
|
197
187
|
const [versions, setVersions] = useState([]);
|
|
198
188
|
const [historyOpen, setHistoryOpen] = useState(false);
|
|
@@ -224,9 +214,9 @@ const TOOLBAR_COMPONENTS = {
|
|
|
224
214
|
if (live && Array.isArray(data))
|
|
225
215
|
setVersions(data);
|
|
226
216
|
}
|
|
227
|
-
catch (
|
|
228
|
-
console.error('[Toolbar:versions] load-failed', { path, error });
|
|
229
|
-
toast.error(
|
|
217
|
+
catch (err) {
|
|
218
|
+
console.error('[Toolbar:versions] load-failed', { path, error: err });
|
|
219
|
+
toast.error(err instanceof Error ? err.message : 'Failed to load doc versions.');
|
|
230
220
|
}
|
|
231
221
|
})();
|
|
232
222
|
return () => {
|
|
@@ -237,6 +227,13 @@ const TOOLBAR_COMPONENTS = {
|
|
|
237
227
|
if (historyOpen && !selectedVersionId && versions[0])
|
|
238
228
|
setSelectedVersionId(versions[0].savedAt);
|
|
239
229
|
}, [historyOpen, selectedVersionId, versions]);
|
|
230
|
+
/**
|
|
231
|
+
* Saves the current document while preventing the toolbar form's default submission.
|
|
232
|
+
*
|
|
233
|
+
* @param event Form event whose browser submission must be cancelled.
|
|
234
|
+
*
|
|
235
|
+
* @return A promise that settles after the save callback finishes or reports an error.
|
|
236
|
+
*/
|
|
240
237
|
const save = async (event) => {
|
|
241
238
|
event.preventDefault();
|
|
242
239
|
if (!toolbar?.save)
|
|
@@ -244,24 +241,31 @@ const TOOLBAR_COMPONENTS = {
|
|
|
244
241
|
try {
|
|
245
242
|
await Promise.resolve(toolbar.save());
|
|
246
243
|
}
|
|
247
|
-
catch (
|
|
248
|
-
console.error('[Docs:save] failed',
|
|
249
|
-
toast.error(
|
|
244
|
+
catch (err) {
|
|
245
|
+
console.error('[Docs:save] failed', err);
|
|
246
|
+
toast.error(err instanceof Error ? err.message : 'Unable to save document.');
|
|
250
247
|
}
|
|
251
248
|
};
|
|
252
249
|
useEffect(() => {
|
|
253
|
-
if (
|
|
250
|
+
if (aMode === 'view')
|
|
254
251
|
return;
|
|
252
|
+
/**
|
|
253
|
+
* Saves the document when the user presses the platform save shortcut.
|
|
254
|
+
*
|
|
255
|
+
* @param event Keyboard event dispatched by the document.
|
|
256
|
+
*
|
|
257
|
+
* @return Nothing; matching shortcuts delegate to the save handler.
|
|
258
|
+
*/
|
|
255
259
|
const onKeyDown = (event) => {
|
|
256
260
|
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 's')
|
|
257
261
|
void save(event);
|
|
258
262
|
};
|
|
259
263
|
document.addEventListener('keydown', onKeyDown);
|
|
260
264
|
return () => document.removeEventListener('keydown', onKeyDown);
|
|
261
|
-
}, [
|
|
265
|
+
}, [aMode, toolbar]);
|
|
262
266
|
if (!editable)
|
|
263
267
|
return null;
|
|
264
|
-
return (_jsx(TooltipProvider, { children: _jsxs("div", { className: "flex items-center gap-1", "data-docs-toolbar-actions": true, children: [_jsx(Mode, { editable: editable, mode:
|
|
268
|
+
return (_jsx(TooltipProvider, { children: _jsxs("div", { className: "flex items-center gap-1", "data-docs-toolbar-actions": true, children: [_jsx(Mode, { editable: editable, mode: aMode, size: size, disabled: !toolbar, onModeChange: (mode) => {
|
|
265
269
|
if (!toolbar)
|
|
266
270
|
return;
|
|
267
271
|
void toolbar.setMode(mode).catch((error) => {
|
|
@@ -269,7 +273,7 @@ const TOOLBAR_COMPONENTS = {
|
|
|
269
273
|
toast.error(error instanceof Error ? error.message : 'Failed to change mode.');
|
|
270
274
|
clearTransition();
|
|
271
275
|
});
|
|
272
|
-
} }),
|
|
276
|
+
} }), aMode === 'edit' && (_jsxs(ButtonGroup, { children: [_jsx(TextTooltip, { content: "Save (\u2318S)", side: "top", align: "center", delayDuration: 400, children: _jsx(UiButton, { size: size, disabled: !toolbar || !toolbar.dirty, loading: toolbar?.busy === 'saving', onMouseDown: preserveSel, onClick: (event) => void save(event), children: "Save" }) }), historyEnabled && (_jsx(TextTooltip, { content: "Version History", side: "top", align: "center", delayDuration: 400, children: _jsx(UiButton, { size: size, className: "px-0.5", disabled: !toolbar, "aria-label": "Version History", onMouseDown: preserveSel, onClick: () => {
|
|
273
277
|
if (versions.length > 0 && !selectedVersionId)
|
|
274
278
|
setSelectedVersionId(versions[0].savedAt);
|
|
275
279
|
setHistoryOpen(true);
|
|
@@ -311,6 +315,7 @@ const TOOLBAR_COMPONENTS = {
|
|
|
311
315
|
let frame = 0;
|
|
312
316
|
/**
|
|
313
317
|
* Handles sync.
|
|
318
|
+
*
|
|
314
319
|
*/
|
|
315
320
|
const sync = () => {
|
|
316
321
|
const view = codeViewOf();
|
|
@@ -322,6 +327,7 @@ const TOOLBAR_COMPONENTS = {
|
|
|
322
327
|
sync();
|
|
323
328
|
/**
|
|
324
329
|
* Handles refresh.
|
|
330
|
+
*
|
|
325
331
|
*/
|
|
326
332
|
const refresh = () => {
|
|
327
333
|
cancelAnimationFrame(frame);
|
|
@@ -664,10 +670,12 @@ const TOOLBAR_COMPONENTS = {
|
|
|
664
670
|
}, [search.query, search.tree]);
|
|
665
671
|
// 5. EMBED OR CREATE LEAF
|
|
666
672
|
/**
|
|
667
|
-
*
|
|
673
|
+
* Creates a page when requested and links the destination into the current document.
|
|
674
|
+
*
|
|
675
|
+
* @param tgtPath Existing destination path, or the initial path for a new page.
|
|
676
|
+
* @param isNew Whether a new page should be created before linking it.
|
|
668
677
|
*
|
|
669
|
-
* @
|
|
670
|
-
* @param isNew - Whether the destination represents a newly created document.
|
|
678
|
+
* @return A promise that settles after the page link is inserted and the editor is restored.
|
|
671
679
|
*/
|
|
672
680
|
const embed = async (tgtPath, isNew = false) => {
|
|
673
681
|
let finalPath = tgtPath;
|
|
@@ -904,6 +912,7 @@ const TOOLBAR_COMPONENTS = {
|
|
|
904
912
|
sync();
|
|
905
913
|
/**
|
|
906
914
|
* Handles refresh.
|
|
915
|
+
*
|
|
907
916
|
*/
|
|
908
917
|
const refresh = () => {
|
|
909
918
|
cancelAnimationFrame(frame);
|
|
@@ -1065,6 +1074,7 @@ const TOOLBAR_COMPONENTS = {
|
|
|
1065
1074
|
useEffect(() => {
|
|
1066
1075
|
/**
|
|
1067
1076
|
* Handles sync.
|
|
1077
|
+
*
|
|
1068
1078
|
*/
|
|
1069
1079
|
const sync = () => {
|
|
1070
1080
|
const view = codeViewOf();
|
|
@@ -1090,6 +1100,11 @@ const TOOLBAR_COMPONENTS = {
|
|
|
1090
1100
|
const saving = toolbar?.busy ?? null;
|
|
1091
1101
|
const dirty = toolbar?.dirty ?? false;
|
|
1092
1102
|
const publishDraft = getDocsHostAdapter()?.publishDraft;
|
|
1103
|
+
/**
|
|
1104
|
+
* Saves pending edits and publishes the active document through the host adapter.
|
|
1105
|
+
*
|
|
1106
|
+
* @return A promise that settles after publishing or reports a user-facing error.
|
|
1107
|
+
*/
|
|
1093
1108
|
const publish = async () => {
|
|
1094
1109
|
if (!publishDraft || !toolbar?.path)
|
|
1095
1110
|
return;
|
|
@@ -1099,8 +1114,8 @@ const TOOLBAR_COMPONENTS = {
|
|
|
1099
1114
|
await publishDraft(toolbar.path);
|
|
1100
1115
|
toast.success('Published.');
|
|
1101
1116
|
}
|
|
1102
|
-
catch (
|
|
1103
|
-
toast.error(
|
|
1117
|
+
catch (err) {
|
|
1118
|
+
toast.error(err instanceof Error ? err.message : 'Unable to publish document.');
|
|
1104
1119
|
}
|
|
1105
1120
|
};
|
|
1106
1121
|
useEffect(() => {
|
|
@@ -1207,9 +1222,11 @@ const TOOLBAR_COMPONENTS = {
|
|
|
1207
1222
|
};
|
|
1208
1223
|
const insert = toolbar?.insert ?? adapter?.insert;
|
|
1209
1224
|
/**
|
|
1210
|
-
*
|
|
1225
|
+
* Dispatches a structured text command when the editor is in edit mode.
|
|
1211
1226
|
*
|
|
1212
1227
|
* @param detail - Toolbar detail describing the requested document update.
|
|
1228
|
+
*
|
|
1229
|
+
* @return `true` after dispatching in edit mode, or `false` when the editor is read-only.
|
|
1213
1230
|
*/
|
|
1214
1231
|
const jsonCmd = (detail) => {
|
|
1215
1232
|
if (mode !== 'edit')
|
|
@@ -1218,10 +1235,12 @@ const TOOLBAR_COMPONENTS = {
|
|
|
1218
1235
|
return true;
|
|
1219
1236
|
};
|
|
1220
1237
|
/**
|
|
1221
|
-
*
|
|
1238
|
+
* Creates a Portable Text block with a fresh key and the supplied field data.
|
|
1239
|
+
*
|
|
1240
|
+
* @param _type Portable Text block type assigned by the caller.
|
|
1241
|
+
* @param val Block fields copied into the new object.
|
|
1222
1242
|
*
|
|
1223
|
-
* @
|
|
1224
|
-
* @param value - Field value being normalized for the toolbar.
|
|
1243
|
+
* @return A block object with a new `_key`, the requested type, and supplied fields.
|
|
1225
1244
|
*/
|
|
1226
1245
|
const jsonBlock = (_type, val) => ({
|
|
1227
1246
|
_key: crypto.randomUUID(),
|
|
@@ -1235,7 +1254,7 @@ const TOOLBAR_COMPONENTS = {
|
|
|
1235
1254
|
* @param fallback - Value passed to the helper.
|
|
1236
1255
|
* @param isInline - Value passed to the helper.
|
|
1237
1256
|
*
|
|
1238
|
-
* @
|
|
1257
|
+
* @return safe Sel.
|
|
1239
1258
|
*/
|
|
1240
1259
|
const sSel = (fallback, isInline = false) => {
|
|
1241
1260
|
let text = '';
|