sol-components 2.1.0
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/README.md +7 -0
- package/core/activate.js +27 -0
- package/core/adopt.js +71 -0
- package/core/auth-core.js +73 -0
- package/core/auth-fetch.js +154 -0
- package/core/component-mount.js +110 -0
- package/core/defaults.js +48 -0
- package/core/define.js +15 -0
- package/core/display-target.js +166 -0
- package/core/edit-placements.js +28 -0
- package/core/editor-self.js +127 -0
- package/core/editor.js +162 -0
- package/core/events.js +27 -0
- package/core/extension-points.js +189 -0
- package/core/form-utils.js +210 -0
- package/core/from-query.js +138 -0
- package/core/from-rdf.js +52 -0
- package/core/here.js +33 -0
- package/core/include-core.js +73 -0
- package/core/inrupt-global.js +18 -0
- package/core/menu-consumer.js +41 -0
- package/core/menu-rdf.js +154 -0
- package/core/pod-ops.js +392 -0
- package/core/pod-registry.js +82 -0
- package/core/popup-proxy.js +255 -0
- package/core/rdf-core.js +280 -0
- package/core/rdf-render.js +136 -0
- package/core/rdf-utils.js +411 -0
- package/core/rdf.js +154 -0
- package/core/services.js +106 -0
- package/core/shape-to-form.js +741 -0
- package/core/sparql-safety.js +20 -0
- package/core/utils.js +196 -0
- package/dist/importmap-cdn.json +49 -0
- package/dist/importmap-local.json +49 -0
- package/dist/sol-loader.manifest.json +140 -0
- package/dist/vendor/@comunica-query-sparql.js +137851 -0
- package/dist/vendor/@inrupt-solid-client-authn-browser.js +7503 -0
- package/dist/vendor/dompurify.js +1476 -0
- package/dist/vendor/ical.js.js +9739 -0
- package/dist/vendor/marked.js +85 -0
- package/dist/vendor/n3.js +14670 -0
- package/dist/vendor/rdf-validate-shacl.js +6970 -0
- package/dist/vendor/rdflib.js +35172 -0
- package/dist/vendor/solid-logic.js +6819 -0
- package/dist/vendor/solid-ui.js +21945 -0
- package/node/sol-form.js +133 -0
- package/node/sol-include.js +55 -0
- package/node/sol-login.js +632 -0
- package/node/sol-menu.js +639 -0
- package/node/sol-query.js +116 -0
- package/package.json +133 -0
- package/web/menu-from-rdf.js +23 -0
- package/web/scripts/prefs.js +25 -0
- package/web/sol-accordion.js +114 -0
- package/web/sol-basic.js +50 -0
- package/web/sol-breadcrumb.js +131 -0
- package/web/sol-button.js +244 -0
- package/web/sol-calendar.js +465 -0
- package/web/sol-default.js +118 -0
- package/web/sol-dropdown-button.js +222 -0
- package/web/sol-feed.js +1336 -0
- package/web/sol-form.js +949 -0
- package/web/sol-full.js +43 -0
- package/web/sol-gallery.js +303 -0
- package/web/sol-include.js +246 -0
- package/web/sol-live-edit.js +415 -0
- package/web/sol-login.js +856 -0
- package/web/sol-menu.js +593 -0
- package/web/sol-modal.js +377 -0
- package/web/sol-pod-extras.js +17 -0
- package/web/sol-pod-ops.js +680 -0
- package/web/sol-pod.js +1039 -0
- package/web/sol-query.js +546 -0
- package/web/sol-rolodex.js +95 -0
- package/web/sol-search.js +402 -0
- package/web/sol-settings.js +199 -0
- package/web/sol-solidos.js +93 -0
- package/web/sol-tabs.js +445 -0
- package/web/sol-time.js +194 -0
- package/web/sol-tree-edit.js +492 -0
- package/web/sol-wac.js +456 -0
- package/web/sol-weather.js +337 -0
- package/web/sol-window.js +142 -0
- package/web/styles/buttons-css.js +108 -0
- package/web/styles/help.css +242 -0
- package/web/styles/root.css +112 -0
- package/web/styles/sol-accordion-css.js +97 -0
- package/web/styles/sol-calendar-css.js +154 -0
- package/web/styles/sol-feed-css.js +475 -0
- package/web/styles/sol-form-css.js +471 -0
- package/web/styles/sol-gallery-css.js +181 -0
- package/web/styles/sol-include-css.js +95 -0
- package/web/styles/sol-live-edit-css.js +84 -0
- package/web/styles/sol-live-edit.css +101 -0
- package/web/styles/sol-login-css.js +116 -0
- package/web/styles/sol-menu-css.js +145 -0
- package/web/styles/sol-modal-css.js +134 -0
- package/web/styles/sol-pod-css.js +187 -0
- package/web/styles/sol-pod-modal-css.js +203 -0
- package/web/styles/sol-query-css.js +140 -0
- package/web/styles/sol-query-help.css +267 -0
- package/web/styles/sol-query-one-pager.css +67 -0
- package/web/styles/sol-search-css.js +157 -0
- package/web/styles/sol-solidos-css.js +7 -0
- package/web/styles/sol-tabs-css.js +114 -0
- package/web/styles/sol-time-css.js +30 -0
- package/web/styles/sol-wac-css.js +73 -0
- package/web/styles/sol-weather-css.js +59 -0
- package/web/styles/solid-logo.svg +9 -0
- package/web/styles/view-accordion-css.js +66 -0
- package/web/styles/view-anchorlist-css.js +22 -0
- package/web/styles/view-autocomplete-css.js +59 -0
- package/web/styles/view-rolodex-css.js +102 -0
- package/web/styles/view-select-css.js +21 -0
- package/web/utils/calendar-fetch.js +388 -0
- package/web/utils/code-mirror-editor.js +82 -0
- package/web/utils/commons-fetch.js +108 -0
- package/web/utils/feed-edit.js +159 -0
- package/web/utils/feed-edit.smoke.mjs +74 -0
- package/web/utils/feed-fetch.js +573 -0
- package/web/utils/live-edit-help/csv.js +64 -0
- package/web/utils/live-edit-help/graphviz.js +41 -0
- package/web/utils/live-edit-help/jsonld.js +55 -0
- package/web/utils/live-edit-help/markdown.js +52 -0
- package/web/utils/live-edit-help/mermaid.js +48 -0
- package/web/utils/live-edit-help/turtle.js +85 -0
- package/web/utils/rdf-config.js +125 -0
- package/web/utils/renderers/csv.js +124 -0
- package/web/utils/renderers/d3-force.js +82 -0
- package/web/utils/renderers/graphviz.js +13 -0
- package/web/utils/renderers/html.js +10 -0
- package/web/utils/renderers/jsonld.js +63 -0
- package/web/utils/renderers/markdown.js +19 -0
- package/web/utils/renderers/mermaid.js +54 -0
- package/web/utils/renderers/turtle.js +51 -0
- package/web/utils/sol-query-triple-patterns.js +151 -0
- package/web/utils/sol-query-ui.js +250 -0
- package/web/utils/sol-query-views.js +32 -0
- package/web/views/_helpers.js +34 -0
- package/web/views/accordion.js +133 -0
- package/web/views/anchorlist.js +59 -0
- package/web/views/auto-complete.js +183 -0
- package/web/views/dl.js +38 -0
- package/web/views/list.js +19 -0
- package/web/views/menu.js +56 -0
- package/web/views/rolodex.js +126 -0
- package/web/views/select.js +79 -0
- package/web/views/table.js +73 -0
- package/web/views/tabs.js +57 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <sol-button> — declarative launcher.
|
|
3
|
+
*
|
|
4
|
+
* Renders an HTML button (the slot contents become its label) that, on
|
|
5
|
+
* click, mounts a `<handler source="…" …>` element inside the element
|
|
6
|
+
* identified by `target`. Uses the same `[data-menu-item="<name>"]`
|
|
7
|
+
* wrapper convention sol-menu's ui:Component items use, so a sol-button
|
|
8
|
+
* launcher coexists with menu-driven items in the same display area.
|
|
9
|
+
* Every (target, name) pair is a persistent tab: clicking the button
|
|
10
|
+
* a second time re-shows the existing mount with all its state intact
|
|
11
|
+
* (login sessions, scroll, open panels, in-flight fetches) instead of
|
|
12
|
+
* tearing it down and rebuilding.
|
|
13
|
+
*
|
|
14
|
+
* Reserved attributes (consumed by sol-button itself):
|
|
15
|
+
* handler — tag name of the component to mount (optional; when absent,
|
|
16
|
+
* inferred from `source`: same-origin → sol-include, external
|
|
17
|
+
* → iframe)
|
|
18
|
+
* region — where the content surfaces. A CSS selector (a pane the page
|
|
19
|
+
* declares) OR a keyword that conjures an ephemeral surface with
|
|
20
|
+
* no author-placed element: modal | floating | tab | window.
|
|
21
|
+
* Resolved by cascade — this attribute, else a parent container,
|
|
22
|
+
* else an enclosing <sol-menu>, else <sol-default>.
|
|
23
|
+
* inline — boolean: toggle the content INLINE into a host, non-keep-alive
|
|
24
|
+
* (see below). The host is resolved through the SAME region cascade
|
|
25
|
+
* (a parent [region] or <sol-default region="#host">), so the host
|
|
26
|
+
* can be declared once on <sol-default> rather than on every button.
|
|
27
|
+
* for — (inline only) explicit host selector, overriding the cascade;
|
|
28
|
+
* defaults to the button's own parent when nothing resolves.
|
|
29
|
+
*
|
|
30
|
+
* `handler` names what the button does — a component OR an action, treated the
|
|
31
|
+
* same way. A custom-element tag (has a "-", e.g. sol-include) is mounted; a
|
|
32
|
+
* bare name that isn't a registered element (e.g. "installPod") is an action:
|
|
33
|
+
* it dispatches `sol-command` (detail.command = the handler) for the host app's
|
|
34
|
+
* registry to resolve, with `params` (JSON or a bare string) as detail.params.
|
|
35
|
+
* name — wrapper identifier (data-menu-item); defaults to the
|
|
36
|
+
* element's id if set, otherwise to a slug of source
|
|
37
|
+
* source — forwarded to the handler (e.g. sol-include's `source`)
|
|
38
|
+
* replace — boolean: rebuild a pane wrapper's contents on every click
|
|
39
|
+
* instead of reusing them.
|
|
40
|
+
*
|
|
41
|
+
* Every OTHER attribute on sol-button is forwarded as-is to the handler
|
|
42
|
+
* element, so authoring is just like inlining the handler:
|
|
43
|
+
*
|
|
44
|
+
* <sol-button handler="sol-include" source="pages/settings.html"
|
|
45
|
+
* target="#dk-content" name="Settings" trusted>
|
|
46
|
+
* ⚙
|
|
47
|
+
* </sol-button>
|
|
48
|
+
*
|
|
49
|
+
* on click → <sol-include source="pages/settings.html" trusted>
|
|
50
|
+
* gets mounted inside #dk-content > [data-menu-item="Settings"]
|
|
51
|
+
*
|
|
52
|
+
* <sol-default region="#main"></sol-default>
|
|
53
|
+
* <sol-button handler="sol-include" inline source="help.html">?</sol-button>
|
|
54
|
+
*
|
|
55
|
+
* click → toggles <sol-include source="help.html"> inside #main (the host
|
|
56
|
+
* from the region cascade; a .sol-inline-panel wrapper); click again
|
|
57
|
+
* removes it. The button gets `open` + aria-expanded while shown.
|
|
58
|
+
*
|
|
59
|
+
* Events:
|
|
60
|
+
* sol-button-activate — detail: { name, handler, wrapper, open? }
|
|
61
|
+
* (`open` is present in inline mode: true on show, false on hide)
|
|
62
|
+
*
|
|
63
|
+
* The trigger button is exposed as `::part(trigger)` for external
|
|
64
|
+
* styling, matching sol-modal's pattern.
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
import { define } from '../core/define.js';
|
|
68
|
+
import { ensureHandler, dispatchCommand, isCommandName } from '../core/rdf-render.js';
|
|
69
|
+
import { displayItem, isExternal, resolveRegion } from '../core/display-target.js';
|
|
70
|
+
|
|
71
|
+
const RESERVED = new Set(['handler', 'region', 'name', 'replace', 'inline', 'for', 'params', 'class', 'style']);
|
|
72
|
+
|
|
73
|
+
class SolButton extends HTMLElement {
|
|
74
|
+
constructor() {
|
|
75
|
+
super();
|
|
76
|
+
this.attachShadow({ mode: 'open' });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
connectedCallback() {
|
|
80
|
+
if (this._rendered) return;
|
|
81
|
+
this._rendered = true;
|
|
82
|
+
this.shadowRoot.innerHTML = `
|
|
83
|
+
<button class="sol-btn sol-button-trigger" part="trigger" type="button">
|
|
84
|
+
<slot></slot>
|
|
85
|
+
</button>`;
|
|
86
|
+
const btn = this.shadowRoot.querySelector('.sol-button-trigger');
|
|
87
|
+
const a11y = this.getAttribute('aria-label') || this.getAttribute('title');
|
|
88
|
+
if (a11y) btn.setAttribute('aria-label', a11y);
|
|
89
|
+
const tip = this.getAttribute('title');
|
|
90
|
+
if (tip) btn.setAttribute('title', tip);
|
|
91
|
+
btn.addEventListener('click', () => this._activate());
|
|
92
|
+
|
|
93
|
+
// Sync our trigger's active state to the page's current tab so the
|
|
94
|
+
// gear (or any sol-button) lights up while its tab is the visible
|
|
95
|
+
// one, even when activation came from elsewhere.
|
|
96
|
+
this._onTabActivate = (e) => {
|
|
97
|
+
btn.classList.toggle('active', e.detail?.name === this._resolveName());
|
|
98
|
+
};
|
|
99
|
+
document.addEventListener('sol-tab-activate', this._onTabActivate);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
disconnectedCallback() {
|
|
103
|
+
if (this._onTabActivate) {
|
|
104
|
+
document.removeEventListener('sol-tab-activate', this._onTabActivate);
|
|
105
|
+
this._onTabActivate = null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
_resolveName() {
|
|
110
|
+
return this.getAttribute('name')
|
|
111
|
+
|| this.id
|
|
112
|
+
|| (this.getAttribute('source') || this.getAttribute('handler') || '').split(/[\/#?]/).filter(Boolean).pop()
|
|
113
|
+
|| this.getAttribute('handler');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Compute the content element to mount: explicit `handler` wins; else infer
|
|
117
|
+
* from the href origin (same-origin → trusted sol-include, external → iframe).
|
|
118
|
+
* Returns { tag, attrs, href, replace }. */
|
|
119
|
+
_handlerSpec() {
|
|
120
|
+
const href = this.getAttribute('source') || null;
|
|
121
|
+
const explicit = this.getAttribute('handler');
|
|
122
|
+
const attrs = [];
|
|
123
|
+
for (const a of this.attributes) {
|
|
124
|
+
if (RESERVED.has(a.name)) continue;
|
|
125
|
+
if (a.name.startsWith('aria-')) continue;
|
|
126
|
+
attrs.push([a.name, a.value]);
|
|
127
|
+
}
|
|
128
|
+
let tag, replace = this.hasAttribute('replace');
|
|
129
|
+
if (explicit) {
|
|
130
|
+
tag = explicit;
|
|
131
|
+
} else if (href && isExternal(href)) {
|
|
132
|
+
tag = 'iframe';
|
|
133
|
+
attrs.push(['src', href]);
|
|
134
|
+
replace = true;
|
|
135
|
+
} else {
|
|
136
|
+
tag = 'sol-include';
|
|
137
|
+
if (href && !attrs.some(([k]) => k === 'trusted')) attrs.push(['trusted', 'true']);
|
|
138
|
+
}
|
|
139
|
+
return { tag, attrs, href, replace };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
_activate() {
|
|
143
|
+
// `handler` names what the button does — a component (a custom-element tag,
|
|
144
|
+
// mounted) OR an action (a bare name that isn't a registered element →
|
|
145
|
+
// dispatch `sol-command` for the app's registry, same allow-list as sol-menu
|
|
146
|
+
// command items). isCommandName() draws the line (custom elements need a -).
|
|
147
|
+
const handler = this.getAttribute('handler');
|
|
148
|
+
if (handler && isCommandName(handler)) {
|
|
149
|
+
const raw = this.getAttribute('params');
|
|
150
|
+
let params;
|
|
151
|
+
if (raw != null) { try { params = JSON.parse(raw); } catch { params = raw; } }
|
|
152
|
+
dispatchCommand(this, handler, params);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (this.hasAttribute('inline')) { this.toggleInline(); return; }
|
|
156
|
+
|
|
157
|
+
const { tag, attrs, href, replace } = this._handlerSpec();
|
|
158
|
+
const ensure = (t) => ensureHandler(t, this, import.meta.url, 'sol-button');
|
|
159
|
+
ensure(tag);
|
|
160
|
+
|
|
161
|
+
const name = this._resolveName();
|
|
162
|
+
const wrapper = displayItem({
|
|
163
|
+
launcher: this, id: null, name, tag, attrs, href, replace, ensure,
|
|
164
|
+
});
|
|
165
|
+
if (wrapper == null) {
|
|
166
|
+
console.warn('<sol-button>: no region resolved — set region= on the button, a container, <sol-menu>, or <sol-default>.');
|
|
167
|
+
}
|
|
168
|
+
this.dispatchEvent(new CustomEvent('sol-button-activate', {
|
|
169
|
+
bubbles: true, composed: true,
|
|
170
|
+
detail: { name, handler: tag, wrapper },
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ── Inline region (region="inline") ─────────────────────────────────────────
|
|
175
|
+
// Toggle the handler INLINE into a page-declared host (`for="<selector>"`,
|
|
176
|
+
// else the button's own parent). Non-keep-alive: the content is built fresh on
|
|
177
|
+
// open and removed on close, so the panel never accumulates state. Open state
|
|
178
|
+
// is reflected as `open` on the host element and aria-expanded on the trigger,
|
|
179
|
+
// so the page can style the trigger (and react via CSS :has()).
|
|
180
|
+
|
|
181
|
+
_inlineHost() {
|
|
182
|
+
// Explicit `for` wins; otherwise resolve through the region cascade
|
|
183
|
+
// (a parent [region] or <sol-default region="…">); else the button's parent.
|
|
184
|
+
const sel = this.getAttribute('for');
|
|
185
|
+
if (sel) { try { return document.querySelector(sel); } catch { return null; } }
|
|
186
|
+
const r = resolveRegion(this, this._resolveName());
|
|
187
|
+
return r.kind === 'element' ? r.element : this.parentElement;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
get inlineOpen() { return !!(this._inlinePanel && this._inlinePanel.isConnected); }
|
|
191
|
+
|
|
192
|
+
toggleInline() { this.inlineOpen ? this.closeInline() : this.openInline(); }
|
|
193
|
+
|
|
194
|
+
openInline() {
|
|
195
|
+
if (this.inlineOpen) return;
|
|
196
|
+
const host = this._inlineHost();
|
|
197
|
+
if (!host) {
|
|
198
|
+
console.warn('<sol-button region="inline">: no host — set for="<selector>" or place the button inside a container.');
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const { tag, attrs } = this._handlerSpec();
|
|
202
|
+
ensureHandler(tag, this, import.meta.url, 'sol-button');
|
|
203
|
+
const panel = document.createElement('div');
|
|
204
|
+
panel.className = 'sol-inline-panel';
|
|
205
|
+
panel.dataset.solInline = this._resolveName();
|
|
206
|
+
const content = document.createElement(tag);
|
|
207
|
+
for (const [k, v] of attrs) content.setAttribute(k, v);
|
|
208
|
+
panel.appendChild(content);
|
|
209
|
+
host.appendChild(panel);
|
|
210
|
+
this._inlinePanel = panel;
|
|
211
|
+
this._reflectOpen(true);
|
|
212
|
+
this.dispatchEvent(new CustomEvent('sol-button-activate', {
|
|
213
|
+
bubbles: true, composed: true,
|
|
214
|
+
detail: { name: this._resolveName(), handler: tag, wrapper: panel, open: true },
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
closeInline() {
|
|
219
|
+
if (!this.inlineOpen) { this._reflectOpen(false); return; }
|
|
220
|
+
this._inlinePanel.remove();
|
|
221
|
+
this._inlinePanel = null;
|
|
222
|
+
this._reflectOpen(false);
|
|
223
|
+
this.dispatchEvent(new CustomEvent('sol-button-activate', {
|
|
224
|
+
bubbles: true, composed: true,
|
|
225
|
+
detail: { name: this._resolveName(), open: false },
|
|
226
|
+
}));
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Public: dismiss the inline panel (e.g. the page closing it on navigation). */
|
|
230
|
+
close() { this.closeInline(); }
|
|
231
|
+
|
|
232
|
+
_reflectOpen(open) {
|
|
233
|
+
this.toggleAttribute('open', open);
|
|
234
|
+
const btn = this.shadowRoot.querySelector('.sol-button-trigger');
|
|
235
|
+
if (btn) {
|
|
236
|
+
btn.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
237
|
+
btn.classList.toggle('active', open);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
define('sol-button', SolButton);
|
|
243
|
+
export { SolButton };
|
|
244
|
+
export default SolButton;
|