@pie-players/pie-players-shared 1.0.0-beta.6 → 1.0.0-beta.8
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 +3 -1
- package/dist/i18n/catalogs.d.ts +20 -13
- package/dist/i18n/catalogs.js +22 -23
- package/dist/i18n/content-language.d.ts +46 -4
- package/dist/i18n/content-language.js +83 -5
- package/dist/i18n/index.d.ts +3 -2
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/language-tags.d.ts +73 -4
- package/dist/i18n/language-tags.js +176 -6
- package/dist/i18n/messages/en-US.d.ts +23 -0
- package/dist/i18n/messages/en-US.js +25 -0
- package/dist/i18n/provider.d.ts +3 -6
- package/dist/i18n/provider.js +5 -15
- package/dist/i18n/types.d.ts +6 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/loaders/ElementLoader.d.ts +1 -1
- package/dist/loaders/element-loader.d.ts +4 -1
- package/dist/loaders/element-loader.js +74 -21
- package/dist/loaders/iife-adapter.d.ts +7 -0
- package/dist/loaders/iife-adapter.js +1 -1
- package/dist/security/private-hosts.d.ts +27 -0
- package/dist/security/private-hosts.js +85 -0
- package/dist/security/validate-style-url.js +2 -2
- package/dist/tools/term-lookup.d.ts +15 -0
- package/dist/tools/term-lookup.js +16 -0
- package/dist/types/index.d.ts +47 -27
- package/dist/types/interchange.d.ts +116 -0
- package/dist/types/interchange.js +1 -0
- package/dist/ui/focus-trap.js +3 -1
- package/dist/ui/fontawesome.d.ts +51 -0
- package/dist/ui/fontawesome.js +122 -0
- package/dist/ui/ime.d.ts +6 -0
- package/dist/ui/ime.js +10 -0
- package/package.json +15 -6
- package/dist/i18n/messages/nl-NL.d.ts +0 -636
- package/dist/i18n/messages/nl-NL.js +0 -636
package/dist/types/index.d.ts
CHANGED
|
@@ -10,8 +10,10 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { FormativeDeliveryPolicy, FormativeItemPolicy, FormativeSectionSlice } from "../formative/types.js";
|
|
12
12
|
import type { TimedMediaSectionData, TimedMediaSectionSessionSlice } from "../timed-media/types.js";
|
|
13
|
+
import type { AdaptationLink, CurriculumStandard, LanguagePolicy, SkillLevel } from "./interchange.js";
|
|
13
14
|
export type { FormativeDeliveryPolicy, FormativeItemPolicy };
|
|
14
15
|
export type { TimedMediaSectionData };
|
|
16
|
+
export type { AdaptationLink, ContentSubstitution, CurriculumStandard, LanguagePolicy, ServedContentIdentity, SkillLevel, } from "./interchange.js";
|
|
15
17
|
export interface BaseEntity {
|
|
16
18
|
id?: string;
|
|
17
19
|
createdAt?: Date;
|
|
@@ -32,12 +34,6 @@ export interface VersionEntity extends BaseEntity {
|
|
|
32
34
|
signature?: string;
|
|
33
35
|
version: SemVer;
|
|
34
36
|
}
|
|
35
|
-
export interface SearchMetaData {
|
|
36
|
-
[key: string]: any;
|
|
37
|
-
}
|
|
38
|
-
export interface SearchMetaDataEntity extends BaseEntity {
|
|
39
|
-
searchMetaData?: SearchMetaData;
|
|
40
|
-
}
|
|
41
37
|
export interface ConfigElements {
|
|
42
38
|
[key: string]: string;
|
|
43
39
|
}
|
|
@@ -69,16 +65,36 @@ export interface ConfigEntity {
|
|
|
69
65
|
export interface ConfigContainerEntity extends BaseEntity {
|
|
70
66
|
config: ConfigEntity;
|
|
71
67
|
}
|
|
72
|
-
export interface PassageEntity extends VersionEntity, ConfigContainerEntity
|
|
68
|
+
export interface PassageEntity extends VersionEntity, ConfigContainerEntity {
|
|
73
69
|
name: string;
|
|
70
|
+
/**
|
|
71
|
+
* BCP 47 tag of the content's language (QTI `xml:lang`). The players render
|
|
72
|
+
* and score it under this language; absent, the section's `env.locale` holds.
|
|
73
|
+
*/
|
|
74
|
+
language?: string;
|
|
75
|
+
/** The source a translated version was adapted from. No player reads it. */
|
|
76
|
+
isAdaptationOf?: AdaptationLink;
|
|
74
77
|
/** QTI/APIP-style accessibility catalogs owned by this passage content. */
|
|
75
78
|
accessibilityCatalogs?: AccessibilityCatalog[];
|
|
79
|
+
/**
|
|
80
|
+
* Standards and skills the content is aligned to. Absent means no data; `[]`
|
|
81
|
+
* means the writer states that none applies. No player reads it.
|
|
82
|
+
*/
|
|
83
|
+
curriculumStandards?: CurriculumStandard[];
|
|
84
|
+
/** DOK and Bloom's classifications, on the same terms. No player reads it. */
|
|
85
|
+
skillLevels?: SkillLevel[];
|
|
76
86
|
retired?: boolean;
|
|
77
87
|
published?: boolean;
|
|
78
|
-
highlights?: Record<string, string[]>;
|
|
79
88
|
}
|
|
80
|
-
export interface ItemEntity extends VersionEntity, ConfigContainerEntity
|
|
89
|
+
export interface ItemEntity extends VersionEntity, ConfigContainerEntity {
|
|
81
90
|
name?: string;
|
|
91
|
+
/**
|
|
92
|
+
* BCP 47 tag of the content's language (QTI `xml:lang`). The players render
|
|
93
|
+
* and score it under this language; absent, the section's `env.locale` holds.
|
|
94
|
+
*/
|
|
95
|
+
language?: string;
|
|
96
|
+
/** The source a translated version was adapted from. No player reads it. */
|
|
97
|
+
isAdaptationOf?: AdaptationLink;
|
|
82
98
|
/**
|
|
83
99
|
* `null` as well as absent, because importers write it: JSON has no
|
|
84
100
|
* `undefined`, so an item transformed from another format carries an
|
|
@@ -87,10 +103,16 @@ export interface ItemEntity extends VersionEntity, ConfigContainerEntity, Search
|
|
|
87
103
|
passage?: string | PassageEntity | null;
|
|
88
104
|
/** QTI/APIP-style accessibility catalogs owned by the item root. */
|
|
89
105
|
accessibilityCatalogs?: AccessibilityCatalog[];
|
|
106
|
+
/**
|
|
107
|
+
* Standards and skills the content is aligned to. Absent means no data; `[]`
|
|
108
|
+
* means the writer states that none applies. No player reads it.
|
|
109
|
+
*/
|
|
110
|
+
curriculumStandards?: CurriculumStandard[];
|
|
111
|
+
/** DOK and Bloom's classifications, on the same terms. No player reads it. */
|
|
112
|
+
skillLevels?: SkillLevel[];
|
|
90
113
|
retired?: boolean;
|
|
91
114
|
published?: boolean;
|
|
92
115
|
configuration?: any;
|
|
93
|
-
highlights?: Record<string, string[]>;
|
|
94
116
|
}
|
|
95
117
|
/**
|
|
96
118
|
* `baseId` and `version` are optional on an entity a section references. They
|
|
@@ -109,20 +131,6 @@ export type ReferencedPassageEntity = Omit<WithOptionalVersion<PassageEntity>, "
|
|
|
109
131
|
export type ReferencedItemEntity = Omit<WithOptionalVersion<ItemEntity>, "passage"> & {
|
|
110
132
|
passage?: string | ReferencedPassageEntity | null;
|
|
111
133
|
};
|
|
112
|
-
/**
|
|
113
|
-
* Metadata specifically for interpretation by clients, typically containing
|
|
114
|
-
* options that are relevant for the user interface. This is not indexed for search.
|
|
115
|
-
*/
|
|
116
|
-
export interface SettingsMetaData {
|
|
117
|
-
[key: string]: any;
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Objects that contain metadata in the settings property, which is NOT indexed for search
|
|
121
|
-
* but typically only relevant for particular client cases.
|
|
122
|
-
*/
|
|
123
|
-
export interface SettingsMetaDataEntity {
|
|
124
|
-
settings?: SettingsMetaData;
|
|
125
|
-
}
|
|
126
134
|
export type RubricBlockView = "author" | "candidate" | "proctor" | "scorer" | "testConstructor" | "tutor";
|
|
127
135
|
export interface RubricBlock {
|
|
128
136
|
identifier?: string;
|
|
@@ -150,7 +158,7 @@ export interface RubricBlock {
|
|
|
150
158
|
* References an item within a section. The item property contains the resolved
|
|
151
159
|
* ItemEntity with its PIE config.
|
|
152
160
|
*/
|
|
153
|
-
export interface AssessmentItemRef extends
|
|
161
|
+
export interface AssessmentItemRef extends BaseEntity {
|
|
154
162
|
id?: string;
|
|
155
163
|
identifier: string;
|
|
156
164
|
title?: string;
|
|
@@ -175,7 +183,7 @@ export interface AssessmentItemRef extends SearchMetaDataEntity {
|
|
|
175
183
|
*/
|
|
176
184
|
formative?: FormativeItemPolicy;
|
|
177
185
|
}
|
|
178
|
-
export interface AssessmentSection extends
|
|
186
|
+
export interface AssessmentSection extends BaseEntity {
|
|
179
187
|
id?: string;
|
|
180
188
|
identifier: string;
|
|
181
189
|
title?: string;
|
|
@@ -484,7 +492,7 @@ export interface PersonalNeedsProfile {
|
|
|
484
492
|
*/
|
|
485
493
|
toolParameters?: ToolParameters;
|
|
486
494
|
}
|
|
487
|
-
export interface AssessmentEntity extends BaseEntity
|
|
495
|
+
export interface AssessmentEntity extends BaseEntity {
|
|
488
496
|
name?: string;
|
|
489
497
|
title?: string;
|
|
490
498
|
identifier?: string;
|
|
@@ -499,6 +507,11 @@ export interface AssessmentEntity extends BaseEntity, SearchMetaDataEntity {
|
|
|
499
507
|
accessibilityCatalogs?: AccessibilityCatalog[];
|
|
500
508
|
/** QTI 3.0: Personal Needs Profile (PNP 3.0) */
|
|
501
509
|
personalNeedsProfile?: PersonalNeedsProfile;
|
|
510
|
+
/**
|
|
511
|
+
* The languages the assessment is offered in, read by a backend that
|
|
512
|
+
* resolves language variants. No player reads it.
|
|
513
|
+
*/
|
|
514
|
+
languagePolicy?: LanguagePolicy;
|
|
502
515
|
/**
|
|
503
516
|
* QTI 3.0: testParts structure (authoritative for QTI format).
|
|
504
517
|
*/
|
|
@@ -548,6 +561,13 @@ export interface ToolParameterMap {
|
|
|
548
561
|
signLanguage: {
|
|
549
562
|
signLang?: string;
|
|
550
563
|
};
|
|
564
|
+
/**
|
|
565
|
+
* `language` is the BCP 47 content language the learner reads items in. A
|
|
566
|
+
* host passes it to delivery as `requestedLanguages`.
|
|
567
|
+
*/
|
|
568
|
+
itemTranslation: {
|
|
569
|
+
language?: string;
|
|
570
|
+
};
|
|
551
571
|
/**
|
|
552
572
|
* `rate` multiplies every playback speed, 1 being the provider's normal
|
|
553
573
|
* speed; `pitch` runs 0–2 with 1 normal; `volume` runs 0–1.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interchange types: backends and authoring tools exchange them, and no player
|
|
3
|
+
* reads them. Their tier is listed on the content-model page.
|
|
4
|
+
*
|
|
5
|
+
* Language variants (PIE-1393): no player reads `AdaptationLink` or
|
|
6
|
+
* `LanguagePolicy`.
|
|
7
|
+
* A language variant is its own item or passage version that declares
|
|
8
|
+
* `language` and, when it is a translation, `isAdaptationOf`. Its family is
|
|
9
|
+
* `isAdaptationOf.baseId ?? baseId`.
|
|
10
|
+
*/
|
|
11
|
+
import type { SemVer } from "./index.js";
|
|
12
|
+
/** The source a translated item or passage was adapted from. */
|
|
13
|
+
export interface AdaptationLink {
|
|
14
|
+
baseId: string;
|
|
15
|
+
/** The source version translated. Absent when provenance is unknown. */
|
|
16
|
+
version?: SemVer;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The languages an assessment offers and what a backend serves when a family
|
|
20
|
+
* has no variant in the requested language.
|
|
21
|
+
*/
|
|
22
|
+
export interface LanguagePolicy {
|
|
23
|
+
/** BCP 47 tags the assessment may be served in. */
|
|
24
|
+
languages: string[];
|
|
25
|
+
/**
|
|
26
|
+
* `"default"` serves an item whose family lacks the requested language in
|
|
27
|
+
* the closest match for the platform default, `en-US` (so `en` or `en-GB`),
|
|
28
|
+
* then its content that declares no language, then its source. Fallback is
|
|
29
|
+
* per item; items sharing a passage fall back together. `"none"` fails the
|
|
30
|
+
* load.
|
|
31
|
+
*/
|
|
32
|
+
fallback: "default" | "none";
|
|
33
|
+
/**
|
|
34
|
+
* `"closest"`, the default, serves the nearest variant in the requested
|
|
35
|
+
* language, so `es-MX` reaches `es` or `es-ES`; `"exact"` serves only an
|
|
36
|
+
* equal tag and leaves anything else to `fallback`.
|
|
37
|
+
*/
|
|
38
|
+
matching?: "closest" | "exact";
|
|
39
|
+
/**
|
|
40
|
+
* `"serve"` serves a variant whose source has a newer release and records
|
|
41
|
+
* it as stale; `"require-current"` treats that variant as missing.
|
|
42
|
+
*/
|
|
43
|
+
staleness: "serve" | "require-current";
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Why the served content differs from what was requested: `"fallback"`, not
|
|
47
|
+
* in a requested language; `"variety"`, in another variety of a requested
|
|
48
|
+
* language, such as `es-ES` for `es-MX`; `"stale"`, a translation of an older
|
|
49
|
+
* source release.
|
|
50
|
+
*/
|
|
51
|
+
export type ContentSubstitution = "fallback" | "stale" | "variety";
|
|
52
|
+
/** The content version a backend served, and the language it served it in. */
|
|
53
|
+
export interface ServedContentIdentity {
|
|
54
|
+
baseId: string;
|
|
55
|
+
version?: SemVer;
|
|
56
|
+
/** The family key, when the served version belongs to a variant family. */
|
|
57
|
+
family?: string;
|
|
58
|
+
/** BCP 47 tag of the served content. */
|
|
59
|
+
servedLanguage?: string;
|
|
60
|
+
substitution?: ContentSubstitution;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* One curriculum standard, skill or competency the content is aligned to
|
|
64
|
+
* (PIE-1381). QTI 3 Curriculum Standards Metadata (CSM 1.1), one entry per
|
|
65
|
+
* `labelledGUID`. Content records direct links only; a framework provider
|
|
66
|
+
* resolves parents, crosswalks and successors on read.
|
|
67
|
+
*/
|
|
68
|
+
export interface CurriculumStandard {
|
|
69
|
+
/**
|
|
70
|
+
* CSM `curriculumStandardsMetadata@providerId`: who issued `guid`, from the
|
|
71
|
+
* provider-id registry on the content-model page, or a host value. Absent
|
|
72
|
+
* means `"AB"` (Academic Benchmarks).
|
|
73
|
+
*/
|
|
74
|
+
providerId?: string;
|
|
75
|
+
/**
|
|
76
|
+
* CSM `labelledGUID/GUID`, as the provider issued it. Stored with its case
|
|
77
|
+
* and compared case-insensitively.
|
|
78
|
+
*/
|
|
79
|
+
guid: string;
|
|
80
|
+
/** CSM `labelledGUID/caseItemURI`, for a CASE framework item. */
|
|
81
|
+
caseItemURI?: string;
|
|
82
|
+
/** CSM `labelledGUID/label`: a display code. Never a key. */
|
|
83
|
+
label?: string;
|
|
84
|
+
/** LOM classification purpose. Absent means `"educational objective"`. */
|
|
85
|
+
purpose?: "educational objective" | "prerequisite" | (string & {});
|
|
86
|
+
/** The record's main standard for this provider. At most one per `providerId`. */
|
|
87
|
+
primary?: boolean;
|
|
88
|
+
/** How the link was made. */
|
|
89
|
+
provenance?: "authored" | "derived" | "imported";
|
|
90
|
+
/**
|
|
91
|
+
* For a derived link: the link it was generated from. An absent
|
|
92
|
+
* `providerId` means `"AB"`.
|
|
93
|
+
*/
|
|
94
|
+
derivedFrom?: {
|
|
95
|
+
providerId?: string;
|
|
96
|
+
guid: string;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* A cognitive-complexity classification of the content (PIE-1381). LOM
|
|
101
|
+
* classification purpose "skill level".
|
|
102
|
+
*/
|
|
103
|
+
export interface SkillLevel {
|
|
104
|
+
/**
|
|
105
|
+
* LOM `taxonPath/source`: `"webb-dok"`, `"blooms-revised"`,
|
|
106
|
+
* `"blooms-original"`, or a host taxonomy.
|
|
107
|
+
*/
|
|
108
|
+
source: string;
|
|
109
|
+
/**
|
|
110
|
+
* LOM `taxon/id`: `"1"` to `"4"` for `webb-dok`; `"remember"` to `"create"`
|
|
111
|
+
* for `blooms-revised`.
|
|
112
|
+
*/
|
|
113
|
+
id: string;
|
|
114
|
+
/** PIE extension: the author's justification. */
|
|
115
|
+
rationale?: string;
|
|
116
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/ui/focus-trap.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { collectFocusable } from "./first-focusable.js";
|
|
2
|
+
import { isComposingKeyEvent } from "./ime.js";
|
|
2
3
|
/**
|
|
3
4
|
* Shadow-aware: a trapped panel almost always hosts a custom element rendering into
|
|
4
5
|
* `shadow: "open"`, and a flat `querySelectorAll` would collect only the panel's own
|
|
@@ -44,7 +45,8 @@ export function createFocusTrap(container, options = {}) {
|
|
|
44
45
|
const wrap = options.wrap ?? true;
|
|
45
46
|
const onKeydown = (event) => {
|
|
46
47
|
if (event.key === "Escape") {
|
|
47
|
-
|
|
48
|
+
// An Escape that cancels an IME composition belongs to the IME.
|
|
49
|
+
if (!options.onEscape || isComposingKeyEvent(event))
|
|
48
50
|
return;
|
|
49
51
|
// Claimed, so a page-wide Escape listener does not also act on it.
|
|
50
52
|
event.preventDefault();
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FontAwesome for `<nds-icon-button>`, which renders its glyph as
|
|
3
|
+
* `<i class="fa-light fa-${name}">` and ships no font of its own.
|
|
4
|
+
*
|
|
5
|
+
* FontAwesome comes from the host page when it links any FA stylesheet.
|
|
6
|
+
* Otherwise `ensureFontAwesome` adds FA Free from the ESM CDN the item player's
|
|
7
|
+
* `loaderOptions` name, jsDelivr by default. Pro is never fetched from here:
|
|
8
|
+
* ui.renaissance.com serves its font files to Renaissance origins only, so a
|
|
9
|
+
* host that licenses it links it itself, as section-demos does through its dev
|
|
10
|
+
* proxy.
|
|
11
|
+
*
|
|
12
|
+
* `fa-light` is a weight only Pro carries. Free has no `.fa-light` rule and its
|
|
13
|
+
* Regular font lacks most toolbar glyphs, so without Pro `applyNdsGlyphVariant`
|
|
14
|
+
* renders every glyph in Solid, the one Free weight that has them all.
|
|
15
|
+
*
|
|
16
|
+
* Roboto comes from the vendored button: its connectedCallback links
|
|
17
|
+
* ui.renaissance.com's Roboto unless the page links a stylesheet whose URL
|
|
18
|
+
* contains `Roboto`.
|
|
19
|
+
*/
|
|
20
|
+
export type NdsGlyphVariant = "fa-light" | "fa-regular" | "fa-solid";
|
|
21
|
+
/**
|
|
22
|
+
* Adds FA Free to `<head>` unless the page already links a FontAwesome
|
|
23
|
+
* stylesheet. Appending Free after a host's Pro would override Pro's
|
|
24
|
+
* `.fa-regular` / `.fa-solid` font-family rules page-wide.
|
|
25
|
+
*
|
|
26
|
+
* A stylesheet that fails to load stays in `<head>` marked
|
|
27
|
+
* `data-pie-load-failed`: no later call requests it again, and no shadow root
|
|
28
|
+
* copies it.
|
|
29
|
+
*/
|
|
30
|
+
export declare function ensureFontAwesome(loaderOptions: {
|
|
31
|
+
esmCdnUrl?: unknown;
|
|
32
|
+
esmCdnProvider?: unknown;
|
|
33
|
+
} | null | undefined): void;
|
|
34
|
+
/**
|
|
35
|
+
* Copies the page's FontAwesome `<link>`s into the shadow root `node` renders
|
|
36
|
+
* in, since `<head>` stylesheets do not cross a shadow boundary. Does nothing
|
|
37
|
+
* when `node` is in the document tree, and runs once per shadow root.
|
|
38
|
+
*
|
|
39
|
+
* A stylesheet still loading is copied once it loads, so the copy comes from
|
|
40
|
+
* the cache; one that fails is not copied, since every copy would request it
|
|
41
|
+
* again. Chromium gives a link a `sheet` even when its load fails, so a failed
|
|
42
|
+
* one is known by its mark.
|
|
43
|
+
*/
|
|
44
|
+
export declare function installFontAwesomeInShadow(node: Node): void;
|
|
45
|
+
/**
|
|
46
|
+
* Renders the `fa-light` glyphs inside `button` in `preferred` when the page
|
|
47
|
+
* links Pro, and in Solid otherwise. Re-applies whenever Lit renders or
|
|
48
|
+
* rewrites the icon's class; the class edit removes `fa-light`, so the
|
|
49
|
+
* callback it triggers is a no-op. Returns the observer's disconnect.
|
|
50
|
+
*/
|
|
51
|
+
export declare function applyNdsGlyphVariant(button: HTMLElement, preferred: NdsGlyphVariant): () => void;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FontAwesome for `<nds-icon-button>`, which renders its glyph as
|
|
3
|
+
* `<i class="fa-light fa-${name}">` and ships no font of its own.
|
|
4
|
+
*
|
|
5
|
+
* FontAwesome comes from the host page when it links any FA stylesheet.
|
|
6
|
+
* Otherwise `ensureFontAwesome` adds FA Free from the ESM CDN the item player's
|
|
7
|
+
* `loaderOptions` name, jsDelivr by default. Pro is never fetched from here:
|
|
8
|
+
* ui.renaissance.com serves its font files to Renaissance origins only, so a
|
|
9
|
+
* host that licenses it links it itself, as section-demos does through its dev
|
|
10
|
+
* proxy.
|
|
11
|
+
*
|
|
12
|
+
* `fa-light` is a weight only Pro carries. Free has no `.fa-light` rule and its
|
|
13
|
+
* Regular font lacks most toolbar glyphs, so without Pro `applyNdsGlyphVariant`
|
|
14
|
+
* renders every glyph in Solid, the one Free weight that has them all.
|
|
15
|
+
*
|
|
16
|
+
* Roboto comes from the vendored button: its connectedCallback links
|
|
17
|
+
* ui.renaissance.com's Roboto unless the page links a stylesheet whose URL
|
|
18
|
+
* contains `Roboto`.
|
|
19
|
+
*/
|
|
20
|
+
import { resolveEsmPackageFileUrl } from "../loaders/esm-adapter.js";
|
|
21
|
+
/** The one FA Free build the players add; `<package>@<version>/<path>`. */
|
|
22
|
+
const FONTAWESOME_FREE_FILE = "@fortawesome/fontawesome-free@6.5.2/css/all.min.css";
|
|
23
|
+
// Matches any FA stylesheet the host page links: `fontawesome.min.css`,
|
|
24
|
+
// `font-awesome.css`, a `/_fa-pro/` proxy, `fontawesome-free@…`.
|
|
25
|
+
const FA_HREF_PATTERN = /font.?awesome|fa-?pro/i;
|
|
26
|
+
const FA_FREE_HREF_PATTERN = /fontawesome-free/i;
|
|
27
|
+
const documentStylesheetLinks = () => Array.from(document.querySelectorAll('link[rel="stylesheet"][href]'));
|
|
28
|
+
const documentFontAwesomeLinks = () => documentStylesheetLinks().filter((link) => FA_HREF_PATTERN.test(link.href));
|
|
29
|
+
/** Whether the page links a FontAwesome build other than Free. */
|
|
30
|
+
const pageLinksFontAwesomePro = () => documentFontAwesomeLinks().some((link) => !FA_FREE_HREF_PATTERN.test(link.href));
|
|
31
|
+
/**
|
|
32
|
+
* Adds FA Free to `<head>` unless the page already links a FontAwesome
|
|
33
|
+
* stylesheet. Appending Free after a host's Pro would override Pro's
|
|
34
|
+
* `.fa-regular` / `.fa-solid` font-family rules page-wide.
|
|
35
|
+
*
|
|
36
|
+
* A stylesheet that fails to load stays in `<head>` marked
|
|
37
|
+
* `data-pie-load-failed`: no later call requests it again, and no shadow root
|
|
38
|
+
* copies it.
|
|
39
|
+
*/
|
|
40
|
+
export function ensureFontAwesome(loaderOptions) {
|
|
41
|
+
if (typeof document === "undefined")
|
|
42
|
+
return;
|
|
43
|
+
if (documentFontAwesomeLinks().length > 0)
|
|
44
|
+
return;
|
|
45
|
+
const href = resolveEsmPackageFileUrl(loaderOptions, FONTAWESOME_FREE_FILE);
|
|
46
|
+
const link = document.createElement("link");
|
|
47
|
+
link.rel = "stylesheet";
|
|
48
|
+
link.href = href;
|
|
49
|
+
link.addEventListener("error", () => {
|
|
50
|
+
link.dataset.pieLoadFailed = "";
|
|
51
|
+
}, { once: true });
|
|
52
|
+
document.head.appendChild(link);
|
|
53
|
+
}
|
|
54
|
+
const mirroredShadowRoots = new WeakSet();
|
|
55
|
+
/**
|
|
56
|
+
* Copies the page's FontAwesome `<link>`s into the shadow root `node` renders
|
|
57
|
+
* in, since `<head>` stylesheets do not cross a shadow boundary. Does nothing
|
|
58
|
+
* when `node` is in the document tree, and runs once per shadow root.
|
|
59
|
+
*
|
|
60
|
+
* A stylesheet still loading is copied once it loads, so the copy comes from
|
|
61
|
+
* the cache; one that fails is not copied, since every copy would request it
|
|
62
|
+
* again. Chromium gives a link a `sheet` even when its load fails, so a failed
|
|
63
|
+
* one is known by its mark.
|
|
64
|
+
*/
|
|
65
|
+
export function installFontAwesomeInShadow(node) {
|
|
66
|
+
const shadow = node.getRootNode();
|
|
67
|
+
if (!(shadow instanceof ShadowRoot) || mirroredShadowRoots.has(shadow)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
mirroredShadowRoots.add(shadow);
|
|
71
|
+
const appendLink = (href) => {
|
|
72
|
+
const present = Array.from(shadow.querySelectorAll('link[rel="stylesheet"]')).some((link) => link.href === href);
|
|
73
|
+
if (!href || present)
|
|
74
|
+
return;
|
|
75
|
+
const link = document.createElement("link");
|
|
76
|
+
link.rel = "stylesheet";
|
|
77
|
+
link.href = href;
|
|
78
|
+
shadow.appendChild(link);
|
|
79
|
+
};
|
|
80
|
+
for (const link of documentFontAwesomeLinks()) {
|
|
81
|
+
if ("pieLoadFailed" in link.dataset)
|
|
82
|
+
continue;
|
|
83
|
+
if (link.sheet) {
|
|
84
|
+
appendLink(link.href);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const settle = (event) => {
|
|
88
|
+
link.removeEventListener("load", settle);
|
|
89
|
+
link.removeEventListener("error", settle);
|
|
90
|
+
if (event.type === "load")
|
|
91
|
+
appendLink(link.href);
|
|
92
|
+
};
|
|
93
|
+
link.addEventListener("load", settle);
|
|
94
|
+
link.addEventListener("error", settle);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Renders the `fa-light` glyphs inside `button` in `preferred` when the page
|
|
99
|
+
* links Pro, and in Solid otherwise. Re-applies whenever Lit renders or
|
|
100
|
+
* rewrites the icon's class; the class edit removes `fa-light`, so the
|
|
101
|
+
* callback it triggers is a no-op. Returns the observer's disconnect.
|
|
102
|
+
*/
|
|
103
|
+
export function applyNdsGlyphVariant(button, preferred) {
|
|
104
|
+
const variant = pageLinksFontAwesomePro() ? preferred : "fa-solid";
|
|
105
|
+
if (variant === "fa-light")
|
|
106
|
+
return () => { };
|
|
107
|
+
const apply = () => {
|
|
108
|
+
for (const icon of button.querySelectorAll("i.fa-light")) {
|
|
109
|
+
icon.classList.remove("fa-light");
|
|
110
|
+
icon.classList.add(variant);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
apply();
|
|
114
|
+
const observer = new MutationObserver(apply);
|
|
115
|
+
observer.observe(button, {
|
|
116
|
+
childList: true,
|
|
117
|
+
subtree: true,
|
|
118
|
+
attributes: true,
|
|
119
|
+
attributeFilter: ["class"],
|
|
120
|
+
});
|
|
121
|
+
return () => observer.disconnect();
|
|
122
|
+
}
|
package/dist/ui/ime.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a keydown belongs to an IME composition, so it must not act as a
|
|
3
|
+
* shortcut. Safari reports `isComposing` false on the Enter that commits a
|
|
4
|
+
* composition and marks it only with `keyCode` 229.
|
|
5
|
+
*/
|
|
6
|
+
export declare function isComposingKeyEvent(event: Pick<KeyboardEvent, "isComposing" | "keyCode">): boolean;
|
package/dist/ui/ime.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** The legacy `keyCode` a browser reports for a keydown the IME consumes. */
|
|
2
|
+
const IME_PROCESS_KEY_CODE = 229;
|
|
3
|
+
/**
|
|
4
|
+
* Whether a keydown belongs to an IME composition, so it must not act as a
|
|
5
|
+
* shortcut. Safari reports `isComposing` false on the Enter that commits a
|
|
6
|
+
* composition and marks it only with `keyCode` 229.
|
|
7
|
+
*/
|
|
8
|
+
export function isComposingKeyEvent(event) {
|
|
9
|
+
return event.isComposing || event.keyCode === IME_PROCESS_KEY_CODE;
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pie-players/pie-players-shared",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Shared runtime + UI utilities for PIE players",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
"types": "./dist/security/index.d.ts",
|
|
30
30
|
"import": "./dist/security/index.js"
|
|
31
31
|
},
|
|
32
|
+
"./security/private-hosts": {
|
|
33
|
+
"types": "./dist/security/private-hosts.d.ts",
|
|
34
|
+
"import": "./dist/security/private-hosts.js"
|
|
35
|
+
},
|
|
32
36
|
"./object": {
|
|
33
37
|
"types": "./dist/object/index.d.ts",
|
|
34
38
|
"import": "./dist/object/index.js"
|
|
@@ -97,6 +101,10 @@
|
|
|
97
101
|
"types": "./dist/ui/content-styles.d.ts",
|
|
98
102
|
"import": "./dist/ui/content-styles.js"
|
|
99
103
|
},
|
|
104
|
+
"./ui/fontawesome": {
|
|
105
|
+
"types": "./dist/ui/fontawesome.d.ts",
|
|
106
|
+
"import": "./dist/ui/fontawesome.js"
|
|
107
|
+
},
|
|
100
108
|
"./tools/term-lookup": {
|
|
101
109
|
"types": "./dist/tools/term-lookup.d.ts",
|
|
102
110
|
"import": "./dist/tools/term-lookup.js"
|
|
@@ -106,9 +114,10 @@
|
|
|
106
114
|
"dist"
|
|
107
115
|
],
|
|
108
116
|
"dependencies": {
|
|
109
|
-
"@pie-element/shared-utils": "0.1.
|
|
117
|
+
"@pie-element/shared-utils": "0.1.6",
|
|
110
118
|
"@pie-lib/math-rendering-module": "6.0.0",
|
|
111
119
|
"dompurify": "^3.4.17",
|
|
120
|
+
"ipaddr.js": "^2.5.0",
|
|
112
121
|
"semver": "^7.8.5"
|
|
113
122
|
},
|
|
114
123
|
"scripts": {
|
|
@@ -122,15 +131,15 @@
|
|
|
122
131
|
"scan-hardcoded": "bun run src/i18n/scripts/scan-hardcoded.ts"
|
|
123
132
|
},
|
|
124
133
|
"devDependencies": {
|
|
125
|
-
"@biomejs/biome": "^2.
|
|
126
|
-
"@happy-dom/global-registrator": "^
|
|
127
|
-
"@pie-element/shared-math-rendering-mathjax": "0.1.
|
|
134
|
+
"@biomejs/biome": "^2.6.4",
|
|
135
|
+
"@happy-dom/global-registrator": "^21.0.4",
|
|
136
|
+
"@pie-element/shared-math-rendering-mathjax": "0.1.8",
|
|
128
137
|
"@playwright/test": "^1.64.1",
|
|
129
138
|
"@types/semver": "^7.8.0",
|
|
130
139
|
"es-module-shims": "^2.8.4",
|
|
131
140
|
"esbuild": "^0.28.2",
|
|
132
141
|
"glob": "^13.0.0",
|
|
133
|
-
"svelte": "^5.57.
|
|
142
|
+
"svelte": "^5.57.3",
|
|
134
143
|
"svelte-check": "^4.7.6",
|
|
135
144
|
"typescript": "^5.9.3"
|
|
136
145
|
},
|