@pie-players/pie-players-shared 1.0.0-beta.0 → 1.0.0-beta.10
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/LICENSE +21 -0
- package/README.md +18 -17
- package/dist/THIRD-PARTY-LICENSES.txt +51 -0
- package/dist/components/vendor/nds/README.md +43 -5
- package/dist/components/vendor/nds/nds-icon-button.d.ts +2 -2
- package/dist/components/vendor/nds/nds-icon-button.js +2 -2
- package/dist/i18n/catalogs.d.ts +25 -13
- package/dist/i18n/catalogs.js +30 -22
- package/dist/i18n/content-language.d.ts +77 -0
- package/dist/i18n/content-language.js +129 -0
- package/dist/i18n/index.d.ts +7 -2
- package/dist/i18n/index.js +5 -2
- package/dist/i18n/language-tags.d.ts +3 -55
- package/dist/i18n/language-tags.js +3 -90
- package/dist/i18n/locale-load-error.d.ts +35 -0
- package/dist/i18n/locale-load-error.js +30 -0
- package/dist/i18n/messages/en-US.d.ts +151 -7
- package/dist/i18n/messages/en-US.js +168 -7
- package/dist/i18n/provider.d.ts +122 -18
- package/dist/i18n/provider.js +315 -133
- package/dist/i18n/pseudo.d.ts +34 -0
- package/dist/i18n/pseudo.js +106 -0
- package/dist/i18n/types.d.ts +19 -3
- package/dist/index.d.ts +16 -20
- package/dist/index.js +19 -19
- package/dist/instrumentation/providers/CompositeInstrumentationProvider.js +2 -1
- package/dist/item-session-control/index.d.ts +16 -0
- package/dist/item-session-control/index.js +5 -0
- package/dist/{formative → item-session-control}/mastery.d.ts +5 -5
- package/dist/{formative → item-session-control}/mastery.js +3 -3
- package/dist/{formative → item-session-control}/outcome.d.ts +3 -3
- package/dist/{formative → item-session-control}/outcome.js +2 -2
- package/dist/{formative → item-session-control}/policy.d.ts +11 -11
- package/dist/{formative → item-session-control}/policy.js +12 -12
- package/dist/item-session-control/session.d.ts +19 -0
- package/dist/{formative → item-session-control}/session.js +12 -12
- package/dist/{formative → item-session-control}/state.d.ts +26 -26
- package/dist/{formative → item-session-control}/state.js +13 -13
- package/dist/{formative → item-session-control}/types.d.ts +38 -40
- package/dist/{formative → item-session-control}/types.js +2 -2
- 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/element-package-spec.d.ts +16 -0
- package/dist/loaders/element-package-spec.js +30 -0
- package/dist/loaders/esm-adapter.d.ts +12 -1
- package/dist/loaders/esm-adapter.js +113 -19
- package/dist/loaders/iife-adapter.d.ts +7 -0
- package/dist/loaders/iife-adapter.js +1 -1
- package/dist/loaders/index.d.ts +2 -1
- package/dist/loaders/index.js +2 -1
- package/dist/loaders/preloaded-registration.d.ts +18 -6
- package/dist/loaders/preloaded-registration.js +44 -9
- package/dist/object/index.d.ts +4 -1
- package/dist/object/index.js +8 -1
- package/dist/pie/config.d.ts +8 -0
- package/dist/pie/config.js +32 -1
- package/dist/pie/index.d.ts +2 -0
- package/dist/pie/index.js +1 -0
- package/dist/pie/math-rendering.d.ts +13 -1
- package/dist/pie/math-rendering.js +54 -1
- package/dist/pie/updates.d.ts +4 -1
- package/dist/pie/updates.js +21 -5
- package/dist/pie/versioned-tag.d.ts +10 -0
- package/dist/pie/versioned-tag.js +27 -0
- package/dist/promise/index.d.ts +10 -0
- package/dist/promise/index.js +16 -0
- package/dist/security/overwide-regions.js +65 -0
- 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/security/wrap-overwide-images.d.ts +6 -2
- package/dist/security/wrap-overwide-images.js +5 -2
- package/dist/security/wrap-overwide-tables.d.ts +6 -2
- package/dist/security/wrap-overwide-tables.js +5 -2
- package/dist/security/wrap-overwide.d.ts +13 -0
- package/dist/security/wrap-overwide.js +68 -3
- package/dist/timed-media/index.d.ts +1 -1
- package/dist/timed-media/index.js +1 -1
- package/dist/timed-media/policy.d.ts +2 -2
- package/dist/timed-media/policy.js +2 -2
- package/dist/timed-media/session.d.ts +1 -1
- package/dist/timed-media/session.js +1 -1
- package/dist/timed-media/types.d.ts +11 -11
- package/dist/tools/term-lookup.d.ts +15 -0
- package/dist/tools/term-lookup.js +16 -0
- package/dist/types/index.d.ts +127 -47
- package/dist/types/interchange.d.ts +116 -0
- package/dist/types/interchange.js +1 -0
- package/dist/ui/content-styles-entry.d.ts +1 -0
- package/dist/ui/content-styles-entry.js +2 -0
- package/dist/ui/content-styles.d.ts +24 -3
- package/dist/ui/content-styles.js +114 -3
- package/dist/ui/focus-trap.d.ts +12 -0
- package/dist/ui/focus-trap.js +41 -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/dist/ui/overlay-containment.d.ts +13 -0
- package/dist/ui/overlay-containment.js +23 -0
- package/dist/ui/overlay-placement.d.ts +28 -0
- package/dist/ui/overlay-placement.js +17 -2
- package/package.json +72 -36
- package/dist/formative/index.d.ts +0 -16
- package/dist/formative/index.js +0 -5
- package/dist/formative/session.d.ts +0 -19
- package/dist/i18n/messages/nl-NL.d.ts +0 -529
- package/dist/i18n/messages/nl-NL.js +0 -529
- package/dist/instrumentation/new-relic-agent.d.ts +0 -20
- package/dist/loaders/module-shim.d.ts +0 -12
- package/dist/pie/authoring-tag.d.ts +0 -6
- package/dist/pie/configure-initialization.d.ts +0 -21
- package/dist/pie/correct-response-env.d.ts +0 -3
- package/dist/pie/element-announcements.d.ts +0 -39
- package/dist/pie/elements-rendered.d.ts +0 -23
- package/dist/pie/initialize-element.d.ts +0 -26
- package/dist/pie/markup-math.d.ts +0 -20
- package/dist/pie/resource-monitor.d.ts +0 -217
- package/dist/security/sanitize-forbidden-lists.d.ts +0 -8
- package/dist/ui/pointer-rotate.d.ts +0 -29
- package/dist/ui/safe-storage.d.ts +0 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PIE Framework contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Shared runtime utilities for the `@pie-players/*` player suite: the element
|
|
4
4
|
loader, PIE config and session helpers, markup security, i18n, and the
|
|
5
|
-
|
|
5
|
+
item session control, timed-media and media contracts. For framework code and host
|
|
6
6
|
integrations that need the helpers the player packages use.
|
|
7
7
|
|
|
8
8
|
## Public Exports
|
|
9
9
|
|
|
10
10
|
```ts
|
|
11
|
-
import { safeLocalStorageGet } from "@pie-players/pie-players-shared";
|
|
12
11
|
import { makeUniqueTags } from "@pie-players/pie-players-shared/pie";
|
|
13
12
|
import { normalizeItemPlayerStrategy } from "@pie-players/pie-players-shared";
|
|
14
13
|
```
|
|
@@ -17,12 +16,13 @@ The subpaths below are the package's `exports`; nothing else is importable.
|
|
|
17
16
|
|
|
18
17
|
| Subpath | Contents |
|
|
19
18
|
| --- | --- |
|
|
20
|
-
| `@pie-players/pie-players-shared` | The root: the loader, PIE
|
|
19
|
+
| `@pie-players/pie-players-shared` | The root: the loader, PIE and security helpers, loader config, instrumentation providers, the item-player strategy helpers, the default bundle host URL (`BUILDER_BUNDLE_URL`), a subset of the shared types, and the UI helpers the tools share (focus trap and focusable lookup, IME composition, overlay containment and placement, pointer drag and gestures, scoped CSS). Attribute coercion, content styles and the object helpers are on their own subpaths only |
|
|
21
20
|
| `/loader-config` | `LoaderConfig` and its defaults: instrumentation (`trackPageActions`, `instrumentationProvider`), resource retry, and IIFE bundle retry |
|
|
22
21
|
| `/security` | The item-markup sanitizer (`sanitizeItemMarkup`, `createDefaultItemMarkupSanitizer`, `buildAuthoringAllowList`), external-stylesheet URL validation, the SVG icon and `style` attribute sanitizers, and the wrappers that put overwide images and tables in a scrollable region |
|
|
22
|
+
| `/security/private-hosts` | `isPrivateHostname` and `isCloudMetadataHostname`, the host classification for a URL a server fetches on someone else's behalf. Node-safe: it loads none of the markup sanitizers |
|
|
23
23
|
| `/object` | `mergeObjectsIgnoringNullUndefined`, `cloneDeep`, `isPlainRecord` |
|
|
24
24
|
| `/types` | The shared types: item, passage, section and session entities, PIE models and controllers, accessibility catalogs, and the [media vocabulary](#media-validation) |
|
|
25
|
-
| `/
|
|
25
|
+
| `/item-session-control` | [Item session control](#item-session-control) |
|
|
26
26
|
| `/timed-media` | [Timed media](#timed-media) |
|
|
27
27
|
| `/media` | [Media validation](#media-validation) |
|
|
28
28
|
| `/pie` | PIE runtime utilities: config helpers, bundle initialization, `ItemController` and the item session contract, session commit and snapshots, authoring helpers, math renderer setup, instrumentation event maps ([PIE utilities](src/pie/README.md)) |
|
|
@@ -32,15 +32,16 @@ The subpaths below are the package's `exports`; nothing else is importable.
|
|
|
32
32
|
| `/i18n/types` | The i18n contract, types only |
|
|
33
33
|
| `/i18n/provider` | `SimpleI18n`, `getDefaultI18n` and `resolveInterfaceI18n`, with the English catalog only |
|
|
34
34
|
| `/i18n/catalogs` | `BUNDLED_LOCALES` and lazy loaders for the bundled locales other than English |
|
|
35
|
-
| `/i18n/language-tags` | BCP 47 language tag normalization and matching |
|
|
36
|
-
| `/nds-icon-button` | `<nds-icon-button>`, an icon button vendored as a prebuilt bundle with Lit inlined; importing it registers the tag. The assessment toolkit and `@pie-players/pie-tool-tts-inline` render it |
|
|
35
|
+
| `/i18n/language-tags` | BCP 47 language tag normalization and matching, re-exported from `@pie-players/pie-language-tags` |
|
|
36
|
+
| `/nds-icon-button` | `<pie-nds-icon-button>`, an icon button vendored as a prebuilt bundle with Lit inlined; importing it registers the tag. The assessment toolkit, the section player and `@pie-players/pie-tool-tts-inline` render it |
|
|
37
37
|
| `/ui/attribute-coercion` | Boolean attribute coercion for custom elements |
|
|
38
38
|
| `/ui/content-styles` | `installContentStyles`, `auditContentStyles` and the opt-out checks behind the item player's content styles |
|
|
39
|
+
| `/ui/fontawesome` | The FontAwesome `<pie-nds-icon-button>` glyphs need: the one FA Free pin, Pro detection, the `<head>` and shadow-root installs, and the glyph weight. The assessment toolkit, the section player and `@pie-players/pie-tool-tts-inline` use it |
|
|
39
40
|
| `/tools/term-lookup` | Term normalization and the lookup session the dictionary tools share; the host supplies the endpoint or a resolver |
|
|
40
41
|
|
|
41
|
-
##
|
|
42
|
+
## Item Session Control
|
|
42
43
|
|
|
43
|
-
`@pie-players/pie-players-shared/
|
|
44
|
+
`@pie-players/pie-players-shared/item-session-control` holds the policy resolution, outcome
|
|
44
45
|
aggregation, Try-state reducer, item view, and mastery rollup that
|
|
45
46
|
`pie-section-player` drives. It is pure (no DOM, no timers, no element
|
|
46
47
|
registry), so it is testable without a browser and importable by an adapter that
|
|
@@ -48,18 +49,18 @@ has no player.
|
|
|
48
49
|
|
|
49
50
|
```ts
|
|
50
51
|
import {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
} from "@pie-players/pie-players-shared/
|
|
52
|
+
aggregateTryOutcome,
|
|
53
|
+
resolveItemSessionControl,
|
|
54
|
+
resolveItemTryView,
|
|
55
|
+
rollupMastery,
|
|
56
|
+
} from "@pie-players/pie-players-shared/item-session-control";
|
|
56
57
|
```
|
|
57
58
|
|
|
58
|
-
The authored half, `
|
|
59
|
-
`
|
|
59
|
+
The authored half, `ItemSessionControlPolicy` on `AssessmentSection` and
|
|
60
|
+
`AssessmentItemRef`, is re-exported from the package
|
|
60
61
|
root and from `/types`, beside the section types it annotates.
|
|
61
62
|
|
|
62
|
-
The contract is [`docs/prds/
|
|
63
|
+
The contract is [`docs/prds/item-session-control-contract.md`](../../docs/prds/item-session-control-contract.md),
|
|
63
64
|
including the QTI 3 mapping and why PIE says **Try** rather than "attempt".
|
|
64
65
|
|
|
65
66
|
## Timed Media
|
|
@@ -92,7 +93,7 @@ re-exported from the package root and from `/types`, beside the section types it
|
|
|
92
93
|
annotates.
|
|
93
94
|
|
|
94
95
|
The contract is [`docs/prds/timed-media-section-contract.md`](../../docs/prds/timed-media-section-contract.md),
|
|
95
|
-
including why cue gate conditions name the
|
|
96
|
+
including why cue gate conditions name the Try vocabulary and why an
|
|
96
97
|
unenforceable policy degrades to advisory rather than failing closed.
|
|
97
98
|
|
|
98
99
|
## Media Validation
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
Third-party software included in this package's bundles, with the licence each is used under.
|
|
2
|
+
|
|
3
|
+
========================================================================
|
|
4
|
+
|
|
5
|
+
es-module-shims 2.8.4
|
|
6
|
+
License: MIT
|
|
7
|
+
|
|
8
|
+
MIT License
|
|
9
|
+
-----------
|
|
10
|
+
|
|
11
|
+
Copyright (C) 2018-2021 Guy Bedford
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
14
|
+
|
|
15
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
18
|
+
|
|
19
|
+
========================================================================
|
|
20
|
+
|
|
21
|
+
lit (pre-bundled in the vendored NDS icon button)
|
|
22
|
+
License: BSD-3-Clause
|
|
23
|
+
|
|
24
|
+
BSD 3-Clause License
|
|
25
|
+
|
|
26
|
+
Copyright (c) 2017 Google LLC. All rights reserved.
|
|
27
|
+
|
|
28
|
+
Redistribution and use in source and binary forms, with or without
|
|
29
|
+
modification, are permitted provided that the following conditions are met:
|
|
30
|
+
|
|
31
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
32
|
+
list of conditions and the following disclaimer.
|
|
33
|
+
|
|
34
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
35
|
+
this list of conditions and the following disclaimer in the documentation
|
|
36
|
+
and/or other materials provided with the distribution.
|
|
37
|
+
|
|
38
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
39
|
+
contributors may be used to endorse or promote products derived from
|
|
40
|
+
this software without specific prior written permission.
|
|
41
|
+
|
|
42
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
43
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
44
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
45
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
46
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
47
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
48
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
49
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
50
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
51
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Vendored: `nds-icon-button`
|
|
2
2
|
|
|
3
3
|
Pre-built bundle of the Renaissance Next Design System (NDS)
|
|
4
|
-
|
|
4
|
+
`nds-icon-button` component, registered here as `<pie-nds-icon-button>`. This is
|
|
5
|
+
the **single source of truth** for
|
|
5
6
|
the button across `@pie-players/*`; consumers import it via the package export
|
|
6
7
|
`@pie-players/pie-players-shared/nds-icon-button` rather than vendoring their
|
|
7
8
|
own copy.
|
|
@@ -12,6 +13,7 @@ Known consumers:
|
|
|
12
13
|
header (chevrons, zoom, close).
|
|
13
14
|
- `@pie-players/pie-tool-tts-inline` — the Text-to-Speech play/pause trigger
|
|
14
15
|
and the "more" overflow control.
|
|
16
|
+
- `@pie-players/pie-section-player` — the items pane's scroll hint.
|
|
15
17
|
|
|
16
18
|
It ships as a pre-built single-file bundle (Lit inlined) so consumers get the
|
|
17
19
|
button without taking a runtime dependency on Lit or the rest of NDS: the Lit
|
|
@@ -27,6 +29,17 @@ lands, so it never leaks into a consumer's own dependency set.
|
|
|
27
29
|
| Last sync commit | `1c728d3` |
|
|
28
30
|
| Bundler | Vite 7 in lib mode, ES output, single-file (Lit inlined) |
|
|
29
31
|
|
|
32
|
+
## Licence
|
|
33
|
+
|
|
34
|
+
The inlined Lit runtime is BSD-3-Clause, Copyright Google LLC. Its `@license`
|
|
35
|
+
comments sit in `nds-icon-button.js` and must survive every refresh, since the
|
|
36
|
+
licence requires the notice to travel with a redistributed copy.
|
|
37
|
+
|
|
38
|
+
The NDS component code is Renaissance's own. The bundle carries no NDS licence
|
|
39
|
+
header and the repository records no separate terms, so it ships inside
|
|
40
|
+
`@pie-players/pie-players-shared` under that package's MIT licence (`LICENSE`).
|
|
41
|
+
Renaissance owns that call; record any different terms here.
|
|
42
|
+
|
|
30
43
|
## Why a vendored bundle, not an npm dep
|
|
31
44
|
|
|
32
45
|
NDS is not currently published to a registry the `@pie-players/*` chain can
|
|
@@ -35,10 +48,22 @@ would force a `lit` dependency plus a chunk of foundations CSS onto every
|
|
|
35
48
|
downstream consumer on lockstep release. A pre-built single-file bundle
|
|
36
49
|
sidesteps both: zero new package deps, the bundle inlines what it needs.
|
|
37
50
|
|
|
51
|
+
## Registered tag
|
|
52
|
+
|
|
53
|
+
The bundle registers `pie-nds-icon-button`, under PIE's prefix. A host page that
|
|
54
|
+
also loads NDS registers upstream's own `nds-icon-button`, often unguarded and
|
|
55
|
+
at a different version; sharing that name would leave whichever copy defines
|
|
56
|
+
second either skipped (PIE's guarded define) or throwing (the host's). Two
|
|
57
|
+
sites are patched: the `Pt("…")` decorator argument at the class registration,
|
|
58
|
+
and the `nds-icon-button { display: inline-block; }` element selector at the top
|
|
59
|
+
of `render()`'s inline `<style>`. The BEM class names (`.nds-icon-button`,
|
|
60
|
+
`.nds-icon-button__icon`, modifiers) stay upstream's, and so do the export path
|
|
61
|
+
and file names.
|
|
62
|
+
|
|
38
63
|
## Idempotent registration (built-in define guard)
|
|
39
64
|
|
|
40
|
-
A host page can load more than one `nds-icon-button` consumer (e.g. the
|
|
41
|
-
and the inline TTS tool), and each would otherwise register
|
|
65
|
+
A host page can load more than one `pie-nds-icon-button` consumer (e.g. the
|
|
66
|
+
toolkit and the inline TTS tool), and each would otherwise register the tag a
|
|
42
67
|
second time and throw `NotSupportedError`. To make registration idempotent
|
|
43
68
|
regardless of load order, the Lit `@customElement` decorator helper (`Pt`) in
|
|
44
69
|
this bundle is patched to guard the define:
|
|
@@ -55,6 +80,18 @@ Re-apply this guard after any refresh from upstream. Because the guard still
|
|
|
55
80
|
contains the literal `customElements.define(` token, this file is allow-listed
|
|
56
81
|
in `scripts/check-ce-define-safety.mjs` (which would otherwise flag it).
|
|
57
82
|
|
|
83
|
+
## One registration per page
|
|
84
|
+
|
|
85
|
+
The tag is registered at most once per page, by whichever consumer reaches it
|
|
86
|
+
first, and that copy serves every consumer. Consumers load the bundle with a
|
|
87
|
+
dynamic `import()` the first time an NDS control is about to render, which is
|
|
88
|
+
only when the host sets `ndsIcons: true`; a page that never opts in neither
|
|
89
|
+
fetches the bundle nor takes the `pie-nds-icon-button` tag. A second copy of the
|
|
90
|
+
bundle at a different version loads without error and is skipped by the define
|
|
91
|
+
guard, so the first copy to register decides the markup and styles every
|
|
92
|
+
consumer sees. A host that loads its own NDS registers upstream's
|
|
93
|
+
`nds-icon-button`, a different tag, and is unaffected.
|
|
94
|
+
|
|
58
95
|
## How this is built and shipped
|
|
59
96
|
|
|
60
97
|
`players-shared` builds with `tsc`, which does not emit static `.js`/`.d.ts`
|
|
@@ -69,6 +106,7 @@ Consuming bundlers treat this module per their own externals config:
|
|
|
69
106
|
- `tool-tts-inline` (Vite lib build) externalizes `players-shared` and its
|
|
70
107
|
subpaths, so its published output imports
|
|
71
108
|
`@pie-players/pie-players-shared/nds-icon-button` from the host.
|
|
109
|
+
- `section-player` externalizes the same specifier for the scroll hint.
|
|
72
110
|
- `assessment-toolkit` builds its CE artifacts with every dependency and peer
|
|
73
111
|
dependency, plus each one's subpaths, as esbuild externals, so this module
|
|
74
112
|
stays a bare external import in those artifacts — resolved by the
|
|
@@ -107,8 +145,8 @@ When a newer `nds-icon-button` is needed:
|
|
|
107
145
|
```
|
|
108
146
|
|
|
109
147
|
Then: `bunx vite build --config vite.self-contained.config.js`.
|
|
110
|
-
4. Copy the output over this file, re-apply the define guard
|
|
111
|
-
the `Last sync commit` row.
|
|
148
|
+
4. Copy the output over this file, re-apply the define guard and the two tag
|
|
149
|
+
renames above, and update the `Last sync commit` row.
|
|
112
150
|
5. Rebuild the consumers (`assessment-toolkit`, `tool-tts-inline`) and verify
|
|
113
151
|
the calculator shell and the TTS trigger still mount and register.
|
|
114
152
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Type surface for the vendored
|
|
2
|
+
* Type surface for the vendored NDS icon button bundle.
|
|
3
3
|
*
|
|
4
4
|
* Consumers import this module for its side effect (it registers the
|
|
5
|
-
* `nds-icon-button` custom element on evaluation). The named export is
|
|
5
|
+
* `pie-nds-icon-button` custom element on evaluation). The named export is
|
|
6
6
|
* provided only so tooling can reference the constructor; the tag is what
|
|
7
7
|
* consumers actually use, via markup or `document.createElement`.
|
|
8
8
|
*/
|
|
@@ -602,7 +602,7 @@ let p = class extends C {
|
|
|
602
602
|
render() {
|
|
603
603
|
return yt`
|
|
604
604
|
<style>
|
|
605
|
-
nds-icon-button {
|
|
605
|
+
pie-nds-icon-button {
|
|
606
606
|
display: inline-block;
|
|
607
607
|
}
|
|
608
608
|
|
|
@@ -819,7 +819,7 @@ b([
|
|
|
819
819
|
_()
|
|
820
820
|
], p.prototype, "shape", 1);
|
|
821
821
|
p = b([
|
|
822
|
-
Pt("nds-icon-button")
|
|
822
|
+
Pt("pie-nds-icon-button")
|
|
823
823
|
], p);
|
|
824
824
|
export {
|
|
825
825
|
p as NdsIconButton
|
package/dist/i18n/catalogs.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The bundled catalog loader: `en-US`, the one statically shipped catalog.
|
|
3
3
|
*
|
|
4
4
|
* Imported by players, never by tools. A tool resolves its provider from the
|
|
5
5
|
* toolkit runtime context and needs only the interface plus the English
|
|
@@ -7,31 +7,43 @@
|
|
|
7
7
|
* into a bundle that never calls `setLocale`, because every tool
|
|
8
8
|
* `vite.config.ts` sets `external: []`.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* alongside the file.
|
|
10
|
+
* `en-US` is the source of truth — the fallback for every missing key in every
|
|
11
|
+
* other locale — so the provider imports it statically and it is always
|
|
12
|
+
* resident. It is the only catalog this package ships: every other locale this
|
|
13
|
+
* repository ships lives in the optional generated tier
|
|
14
|
+
* (`@pie-players/pie-i18n-generated`), whose loaders a host composes after
|
|
15
|
+
* this one. The composed shape is that package's README's wiring example:
|
|
17
16
|
*
|
|
18
|
-
*
|
|
19
|
-
* locale
|
|
17
|
+
* ```ts
|
|
18
|
+
* loadCatalog: (locale) =>
|
|
19
|
+
* loadBundledCatalog(locale).catch(() => loadGeneratedCatalog(locale));
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* A request this function cannot serve rejects, and the provider treats that
|
|
23
|
+
* as "resolve through the fallback chain" rather than an error, so a host
|
|
24
|
+
* locale nothing ships still renders English.
|
|
20
25
|
*
|
|
21
26
|
* @module @pie-players/pie-players-shared/i18n/catalogs
|
|
22
27
|
*/
|
|
23
28
|
import type { BundledLocaleCode, MessageCatalog } from "./types.js";
|
|
24
29
|
/**
|
|
25
|
-
* Every locale tag this repository
|
|
30
|
+
* Every locale tag this repository bundles a catalog for. `en-US` alone: the
|
|
31
|
+
* statically resident source of truth.
|
|
26
32
|
*
|
|
27
33
|
* The provider resolves a request against this list through RFC 4647 lookup and
|
|
28
|
-
* primary-subtag widening, so `
|
|
34
|
+
* primary-subtag widening, so `en`, `en_US` and `en-GB`-without-a-catalog all
|
|
35
|
+
* land on `en-US` unless a composed loader serves the region.
|
|
29
36
|
*/
|
|
30
37
|
export declare const BUNDLED_LOCALES: readonly BundledLocaleCode[];
|
|
31
38
|
/**
|
|
32
39
|
* Load one shipped catalog.
|
|
33
40
|
*
|
|
34
|
-
*
|
|
41
|
+
* `en-US` comes back without a load: it is statically resident, and a host
|
|
42
|
+
* composing this loader into a provider — the generated tier's README pattern,
|
|
43
|
+
* or a pseudo-localization of the English catalog — asks for it by name like
|
|
44
|
+
* any other locale.
|
|
45
|
+
*
|
|
46
|
+
* Rejects for a locale with no bundled catalog; the provider treats that as
|
|
35
47
|
* "resolve through the fallback chain" rather than an error, so a host locale we
|
|
36
48
|
* do not ship still renders.
|
|
37
49
|
*/
|
package/dist/i18n/catalogs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The bundled catalog loader: `en-US`, the one statically shipped catalog.
|
|
3
3
|
*
|
|
4
4
|
* Imported by players, never by tools. A tool resolves its provider from the
|
|
5
5
|
* toolkit runtime context and needs only the interface plus the English
|
|
@@ -7,41 +7,49 @@
|
|
|
7
7
|
* into a bundle that never calls `setLocale`, because every tool
|
|
8
8
|
* `vite.config.ts` sets `external: []`.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* alongside the file.
|
|
10
|
+
* `en-US` is the source of truth — the fallback for every missing key in every
|
|
11
|
+
* other locale — so the provider imports it statically and it is always
|
|
12
|
+
* resident. It is the only catalog this package ships: every other locale this
|
|
13
|
+
* repository ships lives in the optional generated tier
|
|
14
|
+
* (`@pie-players/pie-i18n-generated`), whose loaders a host composes after
|
|
15
|
+
* this one. The composed shape is that package's README's wiring example:
|
|
17
16
|
*
|
|
18
|
-
*
|
|
19
|
-
* locale
|
|
17
|
+
* ```ts
|
|
18
|
+
* loadCatalog: (locale) =>
|
|
19
|
+
* loadBundledCatalog(locale).catch(() => loadGeneratedCatalog(locale));
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* A request this function cannot serve rejects, and the provider treats that
|
|
23
|
+
* as "resolve through the fallback chain" rather than an error, so a host
|
|
24
|
+
* locale nothing ships still renders English.
|
|
20
25
|
*
|
|
21
26
|
* @module @pie-players/pie-players-shared/i18n/catalogs
|
|
22
27
|
*/
|
|
23
|
-
|
|
24
|
-
"nl-NL": () => import("./messages/nl-NL.js"),
|
|
25
|
-
};
|
|
28
|
+
import enUS from "./messages/en-US.js";
|
|
26
29
|
/**
|
|
27
|
-
* Every locale tag this repository
|
|
30
|
+
* Every locale tag this repository bundles a catalog for. `en-US` alone: the
|
|
31
|
+
* statically resident source of truth.
|
|
28
32
|
*
|
|
29
33
|
* The provider resolves a request against this list through RFC 4647 lookup and
|
|
30
|
-
* primary-subtag widening, so `
|
|
34
|
+
* primary-subtag widening, so `en`, `en_US` and `en-GB`-without-a-catalog all
|
|
35
|
+
* land on `en-US` unless a composed loader serves the region.
|
|
31
36
|
*/
|
|
32
|
-
export const BUNDLED_LOCALES = ["en-US"
|
|
37
|
+
export const BUNDLED_LOCALES = ["en-US"];
|
|
33
38
|
/**
|
|
34
39
|
* Load one shipped catalog.
|
|
35
40
|
*
|
|
36
|
-
*
|
|
41
|
+
* `en-US` comes back without a load: it is statically resident, and a host
|
|
42
|
+
* composing this loader into a provider — the generated tier's README pattern,
|
|
43
|
+
* or a pseudo-localization of the English catalog — asks for it by name like
|
|
44
|
+
* any other locale.
|
|
45
|
+
*
|
|
46
|
+
* Rejects for a locale with no bundled catalog; the provider treats that as
|
|
37
47
|
* "resolve through the fallback chain" rather than an error, so a host locale we
|
|
38
48
|
* do not ship still renders.
|
|
39
49
|
*/
|
|
40
50
|
export async function loadBundledCatalog(locale) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
throw new Error(`No bundled i18n catalog for locale: ${locale}`);
|
|
51
|
+
if (locale === "en-US") {
|
|
52
|
+
return enUS;
|
|
44
53
|
}
|
|
45
|
-
|
|
46
|
-
return module.default;
|
|
54
|
+
throw new Error(`No bundled i18n catalog for locale: ${locale}`);
|
|
47
55
|
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content language on the delivery channel.
|
|
3
|
+
*
|
|
4
|
+
* Content language names the language the item's content is written in — a
|
|
5
|
+
* fact about the content, on a separate channel from the interface locale a
|
|
6
|
+
* player publishes to the elements inside it. It reaches the player in
|
|
7
|
+
* `env.locale`, the same channel `env.mode` travels: a delivery fact the
|
|
8
|
+
* container knows and content cannot. Authoring hosts emit it; a host that
|
|
9
|
+
* emits nothing leaves the content unstamped, and nothing is invented — there
|
|
10
|
+
* is no default language for content that names none.
|
|
11
|
+
*
|
|
12
|
+
* The player reflects the resolved language onto its content subtree's root as
|
|
13
|
+
* `lang` and `dir`, so a screen reader takes the content's voice rules and RTL
|
|
14
|
+
* content lays out right to left, independent of the chrome's locale.
|
|
15
|
+
*
|
|
16
|
+
* Content that declares nothing falls back to a default the container names:
|
|
17
|
+
* a section's `runtime.contentLanguage`, or {@link UNDECLARED_CONTENT_LANGUAGE}
|
|
18
|
+
* once the host sets an interface locale, which stamps `lang=""` and
|
|
19
|
+
* `dir="auto"` so the content takes neither the interface's language nor its
|
|
20
|
+
* direction. With neither, undeclared content inherits its context, which keeps
|
|
21
|
+
* hosts that set no interface locale rendering as they always have.
|
|
22
|
+
*/
|
|
23
|
+
import type { TextDirection } from "./types.js";
|
|
24
|
+
/**
|
|
25
|
+
* The content-language default for content that declares no language under a
|
|
26
|
+
* host-set interface locale: `lang=""` names the language unknown and
|
|
27
|
+
* `dir="auto"` takes direction from the content's first strong character.
|
|
28
|
+
*/
|
|
29
|
+
export declare const UNDECLARED_CONTENT_LANGUAGE = "auto";
|
|
30
|
+
/**
|
|
31
|
+
* The default a player stamps on content whose `env` declares no language: the
|
|
32
|
+
* host's content language, else {@link UNDECLARED_CONTENT_LANGUAGE} when the
|
|
33
|
+
* host set an interface locale, else `undefined`, which leaves undeclared
|
|
34
|
+
* content inheriting its context. Inputs are read defensively, since both
|
|
35
|
+
* arrive from attributes.
|
|
36
|
+
*/
|
|
37
|
+
export declare function defaultContentLanguage(options: {
|
|
38
|
+
contentLanguage?: unknown;
|
|
39
|
+
interfaceLocale?: unknown;
|
|
40
|
+
}): string | undefined;
|
|
41
|
+
/** `lang` and `dir` for declared content, or `null` when nothing is declared. */
|
|
42
|
+
export interface ContentLanguageAttributes {
|
|
43
|
+
lang: string;
|
|
44
|
+
dir: TextDirection;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* `lang` and `dir` for the content an `env` describes, or `null` when it
|
|
48
|
+
* declares no usable language. Reads `env.locale` defensively — `env` is
|
|
49
|
+
* pass-through and load-bearing, so anything may arrive — and never invents a
|
|
50
|
+
* default: undeclared content stays unstamped and inherits whatever its
|
|
51
|
+
* context genuinely provides.
|
|
52
|
+
*/
|
|
53
|
+
export declare function contentLanguageAttributes(env: unknown): ContentLanguageAttributes | null;
|
|
54
|
+
/**
|
|
55
|
+
* Stamps the content language onto `target`: `contentLanguageAttributes(env)`,
|
|
56
|
+
* else `fallback` — a tag, or {@link UNDECLARED_CONTENT_LANGUAGE} for
|
|
57
|
+
* `lang=""` and `dir="auto"` — else neither attribute, so a model set can drop
|
|
58
|
+
* the language a previous one declared. A fallback that is not a usable tag
|
|
59
|
+
* counts as absent. No-op without a target.
|
|
60
|
+
*/
|
|
61
|
+
export declare function stampContentLanguage(target: Element | null | undefined, env: unknown, fallback?: string | null): void;
|
|
62
|
+
/**
|
|
63
|
+
* The direction of the first letter in `root`'s text, skipping `script`,
|
|
64
|
+
* `style` and `template`, or `null` when it has none. Letters only, which is
|
|
65
|
+
* where the bidi algorithm's strong characters overwhelmingly sit.
|
|
66
|
+
*/
|
|
67
|
+
export declare function firstStrongDirection(root: Node): TextDirection | null;
|
|
68
|
+
/**
|
|
69
|
+
* The mismatch between undeclared content's script and the direction a
|
|
70
|
+
* fallback stamped on `root`, or `null` when there is none to report: the env
|
|
71
|
+
* declares a language, `root` carries no stamped direction or `dir="auto"`, or
|
|
72
|
+
* the content has no letters.
|
|
73
|
+
*/
|
|
74
|
+
export declare function undeclaredDirectionMismatch(root: Element, env: unknown): {
|
|
75
|
+
stamped: TextDirection;
|
|
76
|
+
script: TextDirection;
|
|
77
|
+
} | null;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content language on the delivery channel.
|
|
3
|
+
*
|
|
4
|
+
* Content language names the language the item's content is written in — a
|
|
5
|
+
* fact about the content, on a separate channel from the interface locale a
|
|
6
|
+
* player publishes to the elements inside it. It reaches the player in
|
|
7
|
+
* `env.locale`, the same channel `env.mode` travels: a delivery fact the
|
|
8
|
+
* container knows and content cannot. Authoring hosts emit it; a host that
|
|
9
|
+
* emits nothing leaves the content unstamped, and nothing is invented — there
|
|
10
|
+
* is no default language for content that names none.
|
|
11
|
+
*
|
|
12
|
+
* The player reflects the resolved language onto its content subtree's root as
|
|
13
|
+
* `lang` and `dir`, so a screen reader takes the content's voice rules and RTL
|
|
14
|
+
* content lays out right to left, independent of the chrome's locale.
|
|
15
|
+
*
|
|
16
|
+
* Content that declares nothing falls back to a default the container names:
|
|
17
|
+
* a section's `runtime.contentLanguage`, or {@link UNDECLARED_CONTENT_LANGUAGE}
|
|
18
|
+
* once the host sets an interface locale, which stamps `lang=""` and
|
|
19
|
+
* `dir="auto"` so the content takes neither the interface's language nor its
|
|
20
|
+
* direction. With neither, undeclared content inherits its context, which keeps
|
|
21
|
+
* hosts that set no interface locale rendering as they always have.
|
|
22
|
+
*/
|
|
23
|
+
import { canonicalLanguageTag } from "./language-tags.js";
|
|
24
|
+
import { localeDirection } from "./provider.js";
|
|
25
|
+
/**
|
|
26
|
+
* The content-language default for content that declares no language under a
|
|
27
|
+
* host-set interface locale: `lang=""` names the language unknown and
|
|
28
|
+
* `dir="auto"` takes direction from the content's first strong character.
|
|
29
|
+
*/
|
|
30
|
+
export const UNDECLARED_CONTENT_LANGUAGE = "auto";
|
|
31
|
+
/**
|
|
32
|
+
* The default a player stamps on content whose `env` declares no language: the
|
|
33
|
+
* host's content language, else {@link UNDECLARED_CONTENT_LANGUAGE} when the
|
|
34
|
+
* host set an interface locale, else `undefined`, which leaves undeclared
|
|
35
|
+
* content inheriting its context. Inputs are read defensively, since both
|
|
36
|
+
* arrive from attributes.
|
|
37
|
+
*/
|
|
38
|
+
export function defaultContentLanguage(options) {
|
|
39
|
+
const named = typeof options.contentLanguage === "string"
|
|
40
|
+
? options.contentLanguage.trim()
|
|
41
|
+
: "";
|
|
42
|
+
if (named)
|
|
43
|
+
return named;
|
|
44
|
+
const requested = typeof options.interfaceLocale === "string"
|
|
45
|
+
? options.interfaceLocale.trim()
|
|
46
|
+
: "";
|
|
47
|
+
return requested ? UNDECLARED_CONTENT_LANGUAGE : undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* `lang` and `dir` for the content an `env` describes, or `null` when it
|
|
51
|
+
* declares no usable language. Reads `env.locale` defensively — `env` is
|
|
52
|
+
* pass-through and load-bearing, so anything may arrive — and never invents a
|
|
53
|
+
* default: undeclared content stays unstamped and inherits whatever its
|
|
54
|
+
* context genuinely provides.
|
|
55
|
+
*/
|
|
56
|
+
export function contentLanguageAttributes(env) {
|
|
57
|
+
const locale = env?.locale;
|
|
58
|
+
if (typeof locale !== "string")
|
|
59
|
+
return null;
|
|
60
|
+
const lang = canonicalLanguageTag(locale);
|
|
61
|
+
if (!lang)
|
|
62
|
+
return null;
|
|
63
|
+
return { lang, dir: localeDirection(lang) };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Stamps the content language onto `target`: `contentLanguageAttributes(env)`,
|
|
67
|
+
* else `fallback` — a tag, or {@link UNDECLARED_CONTENT_LANGUAGE} for
|
|
68
|
+
* `lang=""` and `dir="auto"` — else neither attribute, so a model set can drop
|
|
69
|
+
* the language a previous one declared. A fallback that is not a usable tag
|
|
70
|
+
* counts as absent. No-op without a target.
|
|
71
|
+
*/
|
|
72
|
+
export function stampContentLanguage(target, env, fallback) {
|
|
73
|
+
if (!target)
|
|
74
|
+
return;
|
|
75
|
+
const attributes = contentLanguageAttributes(env) ??
|
|
76
|
+
(fallback === UNDECLARED_CONTENT_LANGUAGE
|
|
77
|
+
? { lang: "", dir: "auto" }
|
|
78
|
+
: contentLanguageAttributes({ locale: fallback }));
|
|
79
|
+
if (attributes) {
|
|
80
|
+
target.setAttribute("lang", attributes.lang);
|
|
81
|
+
target.setAttribute("dir", attributes.dir);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
target.removeAttribute("lang");
|
|
85
|
+
target.removeAttribute("dir");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** Scripts written right to left, for {@link firstStrongDirection}. */
|
|
89
|
+
const RTL_LETTER = /[\p{Script=Arabic}\p{Script=Hebrew}\p{Script=Syriac}\p{Script=Thaana}\p{Script=Nko}\p{Script=Adlam}\p{Script=Hanifi_Rohingya}\p{Script=Mandaic}\p{Script=Samaritan}]/u;
|
|
90
|
+
const LETTER = /\p{L}/u;
|
|
91
|
+
/**
|
|
92
|
+
* The direction of the first letter in `root`'s text, skipping `script`,
|
|
93
|
+
* `style` and `template`, or `null` when it has none. Letters only, which is
|
|
94
|
+
* where the bidi algorithm's strong characters overwhelmingly sit.
|
|
95
|
+
*/
|
|
96
|
+
export function firstStrongDirection(root) {
|
|
97
|
+
const doc = root.ownerDocument ?? root;
|
|
98
|
+
const walker = doc.createTreeWalker(root, 4 /* NodeFilter.SHOW_TEXT */, {
|
|
99
|
+
acceptNode: (node) => node.parentElement?.closest("script, style, template")
|
|
100
|
+
? 2 /* NodeFilter.FILTER_REJECT */
|
|
101
|
+
: 1 /* NodeFilter.FILTER_ACCEPT */,
|
|
102
|
+
});
|
|
103
|
+
for (let node = walker.nextNode(); node; node = walker.nextNode()) {
|
|
104
|
+
for (const char of node.nodeValue ?? "") {
|
|
105
|
+
if (RTL_LETTER.test(char))
|
|
106
|
+
return "rtl";
|
|
107
|
+
if (LETTER.test(char))
|
|
108
|
+
return "ltr";
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The mismatch between undeclared content's script and the direction a
|
|
115
|
+
* fallback stamped on `root`, or `null` when there is none to report: the env
|
|
116
|
+
* declares a language, `root` carries no stamped direction or `dir="auto"`, or
|
|
117
|
+
* the content has no letters.
|
|
118
|
+
*/
|
|
119
|
+
export function undeclaredDirectionMismatch(root, env) {
|
|
120
|
+
if (contentLanguageAttributes(env))
|
|
121
|
+
return null;
|
|
122
|
+
const stamped = root.getAttribute("dir");
|
|
123
|
+
if (stamped !== "ltr" && stamped !== "rtl")
|
|
124
|
+
return null;
|
|
125
|
+
const script = firstStrongDirection(root);
|
|
126
|
+
if (!script)
|
|
127
|
+
return null;
|
|
128
|
+
return script === stamped ? null : { stamped, script };
|
|
129
|
+
}
|