@instructure/platform-modules 0.2.0 → 0.3.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 +5 -5
- package/dist/adapters/canvasGraphql/index.d.ts +1 -1
- package/dist/adapters/canvasGraphql/normalize.d.ts +6 -6
- package/dist/adapters/canvasGraphql/queries.d.ts +2 -2
- package/dist/adapters/inMemory.d.ts +4 -4
- package/dist/adapters/limits.d.ts +4 -4
- package/dist/adapters/types.d.ts +6 -6
- package/dist/cache/keys.d.ts +1 -1
- package/dist/components/FilterChips.d.ts +10 -8
- package/dist/components/FilterChips.d.ts.map +1 -1
- package/dist/components/ModuleCard.d.ts +1 -1
- package/dist/components/ModuleItemRow.d.ts +1 -1
- package/dist/components/ModulesList.d.ts.map +1 -1
- package/dist/components/ModulesList.stories.d.ts +9 -9
- package/dist/components/ModulesList.stories.d.ts.map +1 -1
- package/dist/components/labels.d.ts +3 -3
- package/dist/fixtures/generate.d.ts +1 -1
- package/dist/hooks/constants.d.ts +1 -1
- package/dist/hooks/queryOptions.d.ts +1 -1
- package/dist/hooks/useModuleItemQueries.d.ts +1 -1
- package/dist/hooks/useModuleItems.d.ts +1 -1
- package/dist/hooks/useModules.d.ts +1 -1
- package/dist/i18n.d.ts +2 -2
- package/dist/index.js +760 -770
- package/dist/types/domain.d.ts +3 -3
- package/dist/types/enums.d.ts +2 -2
- package/dist/types/navigation.d.ts +1 -1
- package/dist/types/schemas.d.ts +1 -1
- package/locales/en.json +0 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -58,15 +58,15 @@ every key has a default. A host supplies as much or as little as it wants:
|
|
|
58
58
|
const translations = useMemo(() => ({ pageTitle: 'Learning Path' }), [])
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
The
|
|
61
|
+
The catalog is separately importable when you want to extract from it or build a
|
|
62
62
|
full one — `import en from '@instructure/platform-modules/locales/en.json'`.
|
|
63
63
|
|
|
64
|
-
Resolution walks the host
|
|
64
|
+
Resolution walks the host catalog, then `en.json`, then the key itself, taking the
|
|
65
65
|
first entry that is actually a string. Three consequences worth knowing:
|
|
66
66
|
|
|
67
67
|
- **Rebranding and translating are the same edit.** `{ pageTitle: 'Learning Path' }` is the whole
|
|
68
68
|
of the page-title ask, which is why there is no separate `strings` config key.
|
|
69
|
-
- **A key the
|
|
69
|
+
- **A key the catalog does not carry renders as its own text**, so a host-registered label passes
|
|
70
70
|
through rather than showing a bare key.
|
|
71
71
|
- **Only a string overrides.** `''` blanks a string deliberately; a `null` or a number from an
|
|
72
72
|
untyped host falls back to English rather than rendering `null` or throwing.
|
|
@@ -100,8 +100,8 @@ const translations = useMemo(
|
|
|
100
100
|
|
|
101
101
|
**Always supply `other`, whatever your language.** It is the floor the package falls back to,
|
|
102
102
|
and in most locales it is also a real category — Russian uses it for any count with a decimal
|
|
103
|
-
part, so a
|
|
104
|
-
form needs `other` alone, or just a plain string. Nothing validates a host
|
|
103
|
+
part, so a catalog of only `one`/`few`/`many` renders English at `2.5`. A language with one
|
|
104
|
+
form needs `other` alone, or just a plain string. Nothing validates a host catalog, so this
|
|
105
105
|
is a contract rather than a checked rule.
|
|
106
106
|
|
|
107
107
|
Selection reads the `count` option, which is why it arrives as a number rather than a
|
|
@@ -40,7 +40,7 @@ export interface CanvasGraphqlAdapterOptions {
|
|
|
40
40
|
*/
|
|
41
41
|
studentId?: string | null;
|
|
42
42
|
/**
|
|
43
|
-
* Validate
|
|
43
|
+
* Validate normalized output against the Zod schemas before returning.
|
|
44
44
|
*
|
|
45
45
|
* On by default. This is the check that keeps the GraphQL and REST adapters
|
|
46
46
|
* from drifting, and it is the only place the contract is enforced at
|
|
@@ -2,7 +2,7 @@ import { CompletionRequirement, CompletionRequirementType, Module, ModuleItem, M
|
|
|
2
2
|
/**
|
|
3
3
|
* GraphQL node → domain model.
|
|
4
4
|
*
|
|
5
|
-
* Everything transport-shaped stops here. The three
|
|
5
|
+
* Everything transport-shaped stops here. The three normalization rules from
|
|
6
6
|
* `types/domain.ts` are enforced in this file and nowhere else:
|
|
7
7
|
*
|
|
8
8
|
* 1. **Ids are strings.** Canvas hands back `ID`, which the JSON transport
|
|
@@ -34,7 +34,7 @@ export interface GraphqlSubmission {
|
|
|
34
34
|
submittedAt?: string | null;
|
|
35
35
|
attempt?: number | null;
|
|
36
36
|
missing?: boolean | null;
|
|
37
|
-
/** Per-student, override-applied due date,
|
|
37
|
+
/** Per-student, override-applied due date, denormalized onto the submission. */
|
|
38
38
|
cachedDueDate?: string | null;
|
|
39
39
|
}
|
|
40
40
|
export interface GraphqlSubmissionConnection {
|
|
@@ -196,18 +196,18 @@ export declare function normalizeItemType(content: GraphqlModuleItemContent | nu
|
|
|
196
196
|
*/
|
|
197
197
|
export declare function parseDurationMinutes(value: string | null | undefined): number | null;
|
|
198
198
|
/**
|
|
199
|
-
* Wire string → closed enum, with anything
|
|
199
|
+
* Wire string → closed enum, with anything unrecognized becoming `'unknown'`.
|
|
200
200
|
*
|
|
201
201
|
* Unlike an unmappable item `__typename`, an unknown requirement type is not
|
|
202
202
|
* dropped: the requirement still exists, the student still has to satisfy it,
|
|
203
|
-
* and hiding the row would be a worse lie than
|
|
203
|
+
* and hiding the row would be a worse lie than labeling it vaguely.
|
|
204
204
|
*/
|
|
205
205
|
export declare function normalizeCompletionRequirementType(type: string): CompletionRequirementType;
|
|
206
206
|
export declare function normalizePageInfo(pageInfo: GraphqlPageInfo | null | undefined): PageInfo;
|
|
207
207
|
/**
|
|
208
208
|
* The module-level student state every item in that module is read against.
|
|
209
209
|
*
|
|
210
|
-
* Built once per module and threaded into the item
|
|
210
|
+
* Built once per module and threaded into the item normalizer so the inline and
|
|
211
211
|
* on-demand paths derive the identical status for the identical item — which is
|
|
212
212
|
* why `GET_MODULE_ITEMS` re-reads `progression` alongside its items.
|
|
213
213
|
*/
|
|
@@ -330,7 +330,7 @@ export declare function deriveModuleProgress(node: GraphqlModuleNode, completion
|
|
|
330
330
|
* A single item, or `null` when its content type is outside the closed enum.
|
|
331
331
|
*
|
|
332
332
|
* `dueAt` prefers `submission.cachedDueDate` — the per-student, override-applied
|
|
333
|
-
* date Canvas
|
|
333
|
+
* date Canvas denormalizes onto the submission row — and falls back to
|
|
334
334
|
* `content.dueAt`. That ordering is what closes the gap a live-Canvas probe
|
|
335
335
|
* found: `dueAt` exists on `Assignment` only, `Quiz` has none, and a graded
|
|
336
336
|
* `Discussion` keeps its date on the backing assignment, but all three carry a
|
|
@@ -21,10 +21,10 @@ import { DocumentNode } from 'graphql';
|
|
|
21
21
|
* 3. The response type is a single shape with an optional key, which is
|
|
22
22
|
* exactly how the domain model already treats it (`items?: ModuleItem[]`,
|
|
23
23
|
* where `undefined` means "not fetched"). A second document would force
|
|
24
|
-
* the
|
|
24
|
+
* the normalizer to branch on which document produced the payload.
|
|
25
25
|
*
|
|
26
26
|
* `itemsFirst` bounds the inline item fetch. When a module has more items than
|
|
27
|
-
* that, the
|
|
27
|
+
* that, the normalizer drops the partial list rather than reporting a
|
|
28
28
|
* truncated one — see `normalize.ts`.
|
|
29
29
|
*/
|
|
30
30
|
export declare const GET_MODULES: DocumentNode;
|
|
@@ -9,7 +9,7 @@ import { ModulesDataAdapter } from './types';
|
|
|
9
9
|
* server at all.
|
|
10
10
|
*
|
|
11
11
|
* It is a real implementation of the contract, deliberately: it paginates with
|
|
12
|
-
* opaque cursors,
|
|
12
|
+
* opaque cursors, honors `AbortSignal`, and declines to inline items for modules
|
|
13
13
|
* over `INLINE_ITEM_LIMIT` — so hooks written against it meet the same edges
|
|
14
14
|
* Canvas will hand them, including the one Canvas Career gets wrong.
|
|
15
15
|
*/
|
|
@@ -40,7 +40,7 @@ export interface InMemoryRequest {
|
|
|
40
40
|
export interface InMemoryAdapterOptions {
|
|
41
41
|
/**
|
|
42
42
|
* Invoked once per served request. Test hook for asserting exact request
|
|
43
|
-
* counts, which is how the scaling
|
|
43
|
+
* counts, which is how the scaling behavior is locked in.
|
|
44
44
|
*
|
|
45
45
|
* Receives the operation name for the common case, and the full request for
|
|
46
46
|
* tests that care *which* course or module was asked for.
|
|
@@ -51,8 +51,8 @@ export interface InMemoryAdapterOptions {
|
|
|
51
51
|
* Thrown when a caller asks this adapter for a course it was not built for.
|
|
52
52
|
*
|
|
53
53
|
* A real transport would return that other course's data, or 404. Silently
|
|
54
|
-
* serving the fixture regardless is the one
|
|
55
|
-
* production, so it is the one
|
|
54
|
+
* serving the fixture regardless is the one behavior that could not happen in
|
|
55
|
+
* production, so it is the one behavior the test double must not have.
|
|
56
56
|
*/
|
|
57
57
|
export declare class InMemoryCourseMismatchError extends Error {
|
|
58
58
|
readonly expected: string;
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
* Relay connection, and nothing in `app/graphql/types/module_type.rb` caps it.
|
|
36
36
|
*
|
|
37
37
|
* It would be wrong to conclude GraphQL will inline anything you ask for, though.
|
|
38
|
-
* Canvas runs a query-complexity
|
|
38
|
+
* Canvas runs a query-complexity analyzer, and it charges for the *shape of the
|
|
39
39
|
* request* rather than the size of the result: `first: 100, itemsFirst: 100`
|
|
40
40
|
* scores ~1.5M against a 375,000 ceiling and is rejected outright, even on a
|
|
41
41
|
* course holding thirteen items. So the ceiling is real on both transports — just
|
|
@@ -44,13 +44,13 @@
|
|
|
44
44
|
*
|
|
45
45
|
* The GraphQL adapter therefore applies this same 100 as a deliberate *policy*,
|
|
46
46
|
* so both transports fall back to a per-module fetch at the same point and the
|
|
47
|
-
* hooks see one
|
|
47
|
+
* hooks see one behavior rather than two.
|
|
48
48
|
*/
|
|
49
49
|
export declare const INLINE_ITEM_LIMIT = 100;
|
|
50
50
|
/**
|
|
51
51
|
* Ceiling on `pageSize × inlineItemsFirst` for a single inline request.
|
|
52
52
|
*
|
|
53
|
-
* Canvas runs a GraphQL complexity
|
|
53
|
+
* Canvas runs a GraphQL complexity analyzer and rejects anything over 375,000.
|
|
54
54
|
* Complexity is charged on the **shape of the request, not the size of the
|
|
55
55
|
* result** — so a course with 13 items is rejected just as readily as one with
|
|
56
56
|
* 13,000 if the query asks for `first: 100, itemsFirst: 100`.
|
|
@@ -67,7 +67,7 @@ export declare const INLINE_ITEM_LIMIT = 100;
|
|
|
67
67
|
*
|
|
68
68
|
* That is ~151 per requested item node, so the budget is the largest round
|
|
69
69
|
* product comfortably under 375,000/151 ≈ 2,483. Kept as a product rather than
|
|
70
|
-
* two separate caps because the
|
|
70
|
+
* two separate caps because the analyzer multiplies: 100×20 and 10×100 both fit,
|
|
71
71
|
* 25×100 does not.
|
|
72
72
|
*
|
|
73
73
|
* If a page genuinely needs more than this, it is not an inline page — the
|
package/dist/adapters/types.d.ts
CHANGED
|
@@ -5,18 +5,18 @@ import { ModuleItemsPage, ModulesPage } from '../types/domain';
|
|
|
5
5
|
* An adapter owns exactly three things: how a request is made, what fields it
|
|
6
6
|
* asks for, and how the response becomes the domain model. It owns nothing
|
|
7
7
|
* about caching, pagination policy, or React — those live in the hooks, so
|
|
8
|
-
* that swapping GraphQL for REST changes one file and no
|
|
8
|
+
* that swapping GraphQL for REST changes one file and no behavior.
|
|
9
9
|
*
|
|
10
|
-
* Contract every adapter must
|
|
10
|
+
* Contract every adapter must honor:
|
|
11
11
|
*
|
|
12
12
|
* - **Return a real `pageInfo`.** The GraphQL adapter passes through
|
|
13
13
|
* `endCursor`; the REST adapter derives it from the `Link` header. An
|
|
14
14
|
* adapter that hardcodes `hasNextPage: false` silently truncates, which is
|
|
15
15
|
* the live bug in Canvas Career's modules path today.
|
|
16
|
-
* - **
|
|
16
|
+
* - **Honor `signal`.** Collapsing a module aborts its in-flight request.
|
|
17
17
|
* - **Never invent a cursor.** Pass back what the server gave you; do not
|
|
18
|
-
*
|
|
19
|
-
* - **
|
|
18
|
+
* synthesize offsets client-side.
|
|
19
|
+
* - **Normalize fully.** Output must satisfy the Zod schemas. No transport
|
|
20
20
|
* detail (`_id`, `quiz_lti`, snake_case) may reach a caller.
|
|
21
21
|
*/
|
|
22
22
|
export interface ModulesDataAdapter {
|
|
@@ -27,7 +27,7 @@ export interface ModulesDataAdapter {
|
|
|
27
27
|
* one inline request, or `undefined` for "no transport limit of my own".
|
|
28
28
|
*
|
|
29
29
|
* The transport declares its own ceiling rather than the hooks assuming one.
|
|
30
|
-
* Canvas GraphQL has a complexity
|
|
30
|
+
* Canvas GraphQL has a complexity analyzer that rejects the *shape* of a large
|
|
31
31
|
* inline query (@see INLINE_QUERY_NODE_BUDGET); the in-memory double has no
|
|
32
32
|
* such constraint; REST will have a different one again, bounded by
|
|
33
33
|
* `Api::MAX_PER_PAGE` and response size rather than by query complexity.
|
package/dist/cache/keys.d.ts
CHANGED
|
@@ -80,7 +80,7 @@ export declare function modulesListPrefix(courseId: string): readonly ['platform
|
|
|
80
80
|
*
|
|
81
81
|
* This is the one to reach for when acting on "that module's items" without
|
|
82
82
|
* knowing which view or page size rendered them — invalidating after a mutation,
|
|
83
|
-
* or
|
|
83
|
+
* or canceling in flight requests on collapse.
|
|
84
84
|
*/
|
|
85
85
|
export declare function moduleItemsPrefix(courseId: string, moduleId: string): readonly ['platform-modules', string, 'module', string, 'items'];
|
|
86
86
|
//# sourceMappingURL=keys.d.ts.map
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { ReactElement } from 'react';
|
|
2
2
|
import { ModulesFilterId } from './labels';
|
|
3
3
|
/**
|
|
4
|
-
* The filter row.
|
|
4
|
+
* The filter row: a toggle group, not tabs.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* R3 says "Filter • tabs", but the design draws five independent secondary
|
|
7
|
+
* Buttons under a caption — no tablist, no tabpanel, nothing tying the
|
|
8
|
+
* selection to the list. So `role="group"` + `aria-pressed`, one tab stop per
|
|
9
|
+
* chip. Checked against the mock in FOUND-355; `Tabs` is the wrong component.
|
|
10
|
+
*
|
|
11
|
+
* The selected chip is `primary`, not the mock's tinted `secondary`: the mock's
|
|
12
|
+
* two fills sit 1.25:1 apart where WCAG 1.4.11 wants 3:1, and its blues come
|
|
13
|
+
* from InstUI Button v2, which `ui-buttons@11` does not ship.
|
|
10
14
|
*/
|
|
11
15
|
export interface FilterChipsProps {
|
|
12
16
|
value: ModulesFilterId;
|
|
13
17
|
onChange: (filter: ModulesFilterId) => void;
|
|
14
|
-
/** Per-chip match counts, rendered when supplied. Cheap: module-level only. */
|
|
15
|
-
counts?: Partial<Record<ModulesFilterId, number>>;
|
|
16
18
|
}
|
|
17
19
|
/** @see FilterChipsProps */
|
|
18
|
-
export declare function FilterChips({ value, onChange
|
|
20
|
+
export declare function FilterChips({ value, onChange }: FilterChipsProps): ReactElement;
|
|
19
21
|
//# sourceMappingURL=FilterChips.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterChips.d.ts","sourceRoot":"","sources":["../../src/components/FilterChips.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,OAAO,CAAA;AAEhD,OAAO,EAAmC,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAEhF
|
|
1
|
+
{"version":3,"file":"FilterChips.d.ts","sourceRoot":"","sources":["../../src/components/FilterChips.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,OAAO,CAAA;AAEhD,OAAO,EAAmC,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAEhF;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,eAAe,CAAA;IACtB,QAAQ,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAA;CAC5C;AAED,4BAA4B;AAC5B,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,gBAAgB,GAAG,YAAY,CAmD/E"}
|
|
@@ -33,7 +33,7 @@ export interface ModuleCardProps {
|
|
|
33
33
|
moduleLabel?: string | null;
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* Memoized, which is only useful because its props are now stable.
|
|
37
37
|
*
|
|
38
38
|
* `itemsState` comes from `useModulesPageData`'s per-module cache and `onToggle`
|
|
39
39
|
* from a ref-backed `useCallback`, so a card re-renders when *its own* module
|
|
@@ -8,7 +8,7 @@ export interface ModuleItemRowProps {
|
|
|
8
8
|
navigation?: ModuleItemNavigation;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Memoized because it is the hottest component in the package.
|
|
12
12
|
*
|
|
13
13
|
* `item` is a stable reference out of the query cache and `today` is pinned per
|
|
14
14
|
* mount, so the default shallow comparison is enough. It is what stops one
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModulesList.d.ts","sourceRoot":"","sources":["../../src/components/ModulesList.tsx"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,YAAY,EAA+C,MAAM,OAAO,CAAA;AACtF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AACxD,OAAO,KAAK,EAAU,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAG5D,OAAO,EAA4C,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAGzF;;;;;;;;;;;;;;;;GAgBG;AAEH,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,IAAI,EAAE,wBAAwB,CAAA;IAC9B,kCAAkC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,KAAK,CAAC,EAAE,IAAI,CAAA;IACZ;;;;;OAKG;IACH,aAAa,CAAC,EAAE,oBAAoB,CAAA;IACpC,sGAAsG;IACtG,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,eAAe,CAAA;IAC/B,6DAA6D;IAC7D,UAAU,CAAC,EAAE,oBAAoB,CAAA;IACjC;;;;;;;OAOG;IACH,EAAE,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,CAAA;IAC/B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;CAClC;AA0DD,4BAA4B;AAC5B,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,UAAU,EACV,aAAa,EACb,KAAK,EACL,aAAa,EACb,eAA6C,EAC7C,aAAqB,EACrB,UAAU,EACV,EAAU,EACV,YAAmB,GACpB,EAAE,gBAAgB,GAAG,YAAY,
|
|
1
|
+
{"version":3,"file":"ModulesList.d.ts","sourceRoot":"","sources":["../../src/components/ModulesList.tsx"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,YAAY,EAA+C,MAAM,OAAO,CAAA;AACtF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AACxD,OAAO,KAAK,EAAU,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAG5D,OAAO,EAA4C,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAGzF;;;;;;;;;;;;;;;;GAgBG;AAEH,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,IAAI,EAAE,wBAAwB,CAAA;IAC9B,kCAAkC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,KAAK,CAAC,EAAE,IAAI,CAAA;IACZ;;;;;OAKG;IACH,aAAa,CAAC,EAAE,oBAAoB,CAAA;IACpC,sGAAsG;IACtG,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,eAAe,CAAA;IAC/B,6DAA6D;IAC7D,UAAU,CAAC,EAAE,oBAAoB,CAAA;IACjC;;;;;;;OAOG;IACH,EAAE,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,CAAA;IAC/B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;CAClC;AA0DD,4BAA4B;AAC5B,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,UAAU,EACV,aAAa,EACb,KAAK,EACL,aAAa,EACb,eAA6C,EAC7C,aAAqB,EACrB,UAAU,EACV,EAAU,EACV,YAAmB,GACpB,EAAE,gBAAgB,GAAG,YAAY,CAiRjC"}
|
|
@@ -43,21 +43,21 @@ interface ModulesListStoryProps {
|
|
|
43
43
|
/**
|
|
44
44
|
* Which i18n bridge to render through.
|
|
45
45
|
*
|
|
46
|
-
* `none` is a host that supplies no
|
|
46
|
+
* `none` is a host that supplies no catalog: every string comes from
|
|
47
47
|
* `locales/en.json`. `pseudo` is the standard pre-translation audit — every
|
|
48
48
|
* string is bracketed and padded, so an untranslated literal is visible on
|
|
49
49
|
* sight and a layout that cannot survive a longer language shows up before a
|
|
50
|
-
* translator is ever involved. `rebranded` and `partial` are host
|
|
50
|
+
* translator is ever involved. `rebranded` and `partial` are host catalogs,
|
|
51
51
|
* and both are deliberately incomplete.
|
|
52
52
|
*/
|
|
53
53
|
i18n: 'none' | 'pseudo' | 'rebranded' | 'partial';
|
|
54
|
-
/** Clear it to render the
|
|
54
|
+
/** Clear it to render the catalog's `pageTitle` instead of a host-supplied name. */
|
|
55
55
|
courseName: string;
|
|
56
56
|
navigation: 'none' | 'rewritten' | 'intercepted';
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
59
|
* Its own `QueryClient`, deliberately — the global preview decorator builds one
|
|
60
|
-
* in its render body, and these stories are about cache
|
|
60
|
+
* in its render body, and these stories are about cache behavior.
|
|
61
61
|
*/
|
|
62
62
|
declare function ModulesListHarness(props: ModulesListStoryProps): ReactElement;
|
|
63
63
|
declare const meta: Meta<typeof ModulesListHarness>;
|
|
@@ -144,12 +144,12 @@ export declare const StatusCoverage: Story;
|
|
|
144
144
|
* The one deliberate exception is the dev diagnostics banner, which is developer
|
|
145
145
|
* text and is documented as untranslated in `ModuleCard`.
|
|
146
146
|
*/
|
|
147
|
-
export declare const
|
|
147
|
+
export declare const PseudoLocalized: Story;
|
|
148
148
|
/**
|
|
149
149
|
* A host rebranding the page in its own language.
|
|
150
150
|
*
|
|
151
151
|
* Career calls the page a Learning Path and its modules units. That is a
|
|
152
|
-
*
|
|
152
|
+
* catalog entry, not a config key — six entries here, and every string they do
|
|
153
153
|
* not name still reads English from `locales/en.json`. Switch the `fixture`
|
|
154
154
|
* control to `empty` to see the rebranded empty state.
|
|
155
155
|
*/
|
|
@@ -157,10 +157,10 @@ export declare const HostRebrand: Story;
|
|
|
157
157
|
/**
|
|
158
158
|
* A deliberately incomplete translation.
|
|
159
159
|
*
|
|
160
|
-
* Four German keys against an English
|
|
160
|
+
* Four German keys against an English catalog: the filter row is translated
|
|
161
161
|
* and everything else falls back rather than throwing or rendering blank. This
|
|
162
162
|
* is the property that lets a host adopt the package before translating it, and
|
|
163
|
-
* `locale` travels with the
|
|
163
|
+
* `locale` travels with the catalog so `Intl` dates match the words.
|
|
164
164
|
*/
|
|
165
|
-
export declare const
|
|
165
|
+
export declare const PartialCatalog: Story;
|
|
166
166
|
//# sourceMappingURL=ModulesList.stories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModulesList.stories.d.ts","sourceRoot":"","sources":["../../src/components/ModulesList.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAEtD,OAAO,EAAE,KAAK,YAAY,EAAqB,MAAM,OAAO,CAAA;AAE5D,OAAO,EASL,KAAK,eAAe,EACpB,KAAK,SAAS,EAKf,MAAM,UAAU,CAAA;AACjB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG/C;;;;;;;;;;;;GAYG;AAEH,QAAA,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,eAAe,CAMnD,CAAA;AAoBD;;;;;;;;;;GAUG;AAIH,KAAK,YAAY,GAAG,SAAS,GAAG,SAAS,CAAA;AAEzC,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,OAAO,QAAQ,CAAA;IAC9B,SAAS,EAAE,SAAS,CAAA;IACpB,YAAY,EAAE,YAAY,CAAA;IAC1B,aAAa,EAAE,eAAe,CAAA;IAC9B,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAA;IAChB,oEAAoE;IACpE,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;IACvB,oFAAoF;IACpF,wBAAwB,EAAE,MAAM,EAAE,CAAA;IAClC;;;;;;;;;OASG;IACH,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAA;IACjD,
|
|
1
|
+
{"version":3,"file":"ModulesList.stories.d.ts","sourceRoot":"","sources":["../../src/components/ModulesList.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAEtD,OAAO,EAAE,KAAK,YAAY,EAAqB,MAAM,OAAO,CAAA;AAE5D,OAAO,EASL,KAAK,eAAe,EACpB,KAAK,SAAS,EAKf,MAAM,UAAU,CAAA;AACjB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG/C;;;;;;;;;;;;GAYG;AAEH,QAAA,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,eAAe,CAMnD,CAAA;AAoBD;;;;;;;;;;GAUG;AAIH,KAAK,YAAY,GAAG,SAAS,GAAG,SAAS,CAAA;AAEzC,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,OAAO,QAAQ,CAAA;IAC9B,SAAS,EAAE,SAAS,CAAA;IACpB,YAAY,EAAE,YAAY,CAAA;IAC1B,aAAa,EAAE,eAAe,CAAA;IAC9B,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAA;IAChB,oEAAoE;IACpE,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;IACvB,oFAAoF;IACpF,wBAAwB,EAAE,MAAM,EAAE,CAAA;IAClC;;;;;;;;;OASG;IACH,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAA;IACjD,oFAAoF;IACpF,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,GAAG,WAAW,GAAG,aAAa,CAAA;CACjD;AAkJD;;;GAGG;AACH,iBAAS,kBAAkB,CAAC,KAAK,EAAE,qBAAqB,GAAG,YAAY,CAetE;AAkBD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,kBAAkB,CAiCzC,CAAA;AAED,eAAe,IAAI,CAAA;AACnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAA;AAElC;;;;;GAKG;AACH,eAAO,MAAM,OAAO,EAAE,KAErB,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,EAAE,KAEzB,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,EAAE,KAErC,CAAA;AAED,6FAA6F;AAC7F,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAA;AAED,mFAAmF;AACnF,eAAO,MAAM,uBAAuB,EAAE,KAErC,CAAA;AAED,4EAA4E;AAC5E,eAAO,MAAM,yBAAyB,EAAE,KAEvC,CAAA;AAED,mCAAmC;AACnC,eAAO,MAAM,WAAW,EAAE,KAEzB,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAEnC,CAAA;AASD,2CAA2C;AAC3C,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAA;AAED,4DAA4D;AAC5D,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAE/B,CAAA;AAED,mCAAmC;AACnC,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,EAAE,KAO7B,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,EAAE,KAQzB,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,EAAE,KAO5B,CAAA"}
|
|
@@ -29,9 +29,9 @@ export declare function formatPoints(t: TranslateFunction, pointsPossible: numbe
|
|
|
29
29
|
* The requirement column, e.g. "Submit the assignment".
|
|
30
30
|
*
|
|
31
31
|
* Exhaustive over `CompletionRequirementType` — no `default`, so adding a member
|
|
32
|
-
* to the enum is a compile error here rather than a silently
|
|
32
|
+
* to the enum is a compile error here rather than a silently unlabeled row. The
|
|
33
33
|
* `unknown` member is what absorbs a seventh Canvas type, and it still renders
|
|
34
|
-
* something: an
|
|
34
|
+
* something: an unlabeled requirement would look like *no* requirement, which
|
|
35
35
|
* is the wrong failure.
|
|
36
36
|
*/
|
|
37
37
|
export declare function requirementLabel(t: TranslateFunction, requirement: CompletionRequirement): string;
|
|
@@ -75,7 +75,7 @@ export declare function moduleMatchesFilter(module: Module, filter: ModulesFilte
|
|
|
75
75
|
*
|
|
76
76
|
* Same reason as the filters: with `onDemand` pagination the items of collapsed
|
|
77
77
|
* modules are not in memory, so an item-level search would silently under-report
|
|
78
|
-
* — the one thing this package exists to prevent. The input is
|
|
78
|
+
* — the one thing this package exists to prevent. The input is labeled
|
|
79
79
|
* "Search module names" so the limit is on screen rather than in a comment.
|
|
80
80
|
*
|
|
81
81
|
* `toLocaleLowerCase` rather than `toLowerCase`: the Turkish dotless i is the
|
|
@@ -21,7 +21,7 @@ export declare const FIXTURE_COURSE_ID = "1";
|
|
|
21
21
|
*
|
|
22
22
|
* - `student` — everything is published, and every module carries a `progress`
|
|
23
23
|
* with every item a `status`. A student's module list contains no unpublished
|
|
24
|
-
* content at all; that is exactly why
|
|
24
|
+
* content at all; that is exactly why normalization rule 2 reads a null
|
|
25
25
|
* `published` as `true` for a viewer without manage permission.
|
|
26
26
|
* - `teacher` — publish state varies, and nothing carries progress. Canvas
|
|
27
27
|
* resolves `progression` to null for a viewer with no progression record, so a
|
|
@@ -22,7 +22,7 @@ export declare const DEFAULT_ITEM_CONCURRENCY: number;
|
|
|
22
22
|
* Why this is not zero.
|
|
23
23
|
*
|
|
24
24
|
* With `staleTime: 0` every re-enable of a query — which is what re-expanding a
|
|
25
|
-
* module is — counts as stale and refetches. That is the
|
|
25
|
+
* module is — counts as stale and refetches. That is the behavior this package
|
|
26
26
|
* exists to remove. Five minutes is long enough that expand/collapse within a
|
|
27
27
|
* sitting is free, short enough that coming back to the tab later is honest.
|
|
28
28
|
*/
|
|
@@ -15,7 +15,7 @@ import { ModuleItemsPage, ModulesPage } from '../types/domain';
|
|
|
15
15
|
*/
|
|
16
16
|
/**
|
|
17
17
|
* The page cursor. `null` is the first page — the adapter contract forbids
|
|
18
|
-
*
|
|
18
|
+
* synthesizing cursors, so this is only ever `null` or something a server said.
|
|
19
19
|
*/
|
|
20
20
|
export type ModulesCursor = string | null;
|
|
21
21
|
export type ModulesQueryOptions = InfiniteQueryObserverOptions<ModulesPage, Error, InfiniteData<ModulesPage, ModulesCursor>, ModulesListKey, ModulesCursor>;
|
|
@@ -48,7 +48,7 @@ export interface ModuleItemQueries {
|
|
|
48
48
|
export declare function useModuleItemQueries(
|
|
49
49
|
/** Modules whose items should be fetching right now. */
|
|
50
50
|
activeModuleIds: readonly string[],
|
|
51
|
-
/** Must be referentially stable —
|
|
51
|
+
/** Must be referentially stable — memoize it in the caller. */
|
|
52
52
|
buildOptions: (moduleId: string, enabled: boolean) => ModuleItemsQueryOptions,
|
|
53
53
|
/** @see DEFAULT_RETAIN_COLLAPSED_LIMIT */
|
|
54
54
|
retainCollapsedLimit?: number): ModuleItemQueries;
|
|
@@ -31,7 +31,7 @@ export interface UseModuleItemsResult {
|
|
|
31
31
|
* One module's items, paged explicitly, keyed per module.
|
|
32
32
|
*
|
|
33
33
|
* The query's `AbortSignal` is handed to the adapter (in `queryOptions.ts`), so
|
|
34
|
-
*
|
|
34
|
+
* canceling the query — which is what collapsing a module does — aborts the
|
|
35
35
|
* request rather than letting a response nobody wants land in the cache.
|
|
36
36
|
*
|
|
37
37
|
* `useModulesPageData` is the hook a page should use; this one is for a caller
|
|
@@ -42,7 +42,7 @@ export interface UseModulesResult {
|
|
|
42
42
|
*
|
|
43
43
|
* Deliberately *not* `useAllPages`: that helper walks every page on mount and
|
|
44
44
|
* again on every invalidation, which is the mechanism behind Canvas's
|
|
45
|
-
* "expand a module, refetch the course"
|
|
45
|
+
* "expand a module, refetch the course" behavior. Here one call is one page,
|
|
46
46
|
* and `hasNextPage` is surfaced so an unfetched remainder is visible to the
|
|
47
47
|
* caller instead of silently dropped.
|
|
48
48
|
*/
|
package/dist/i18n.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export type PluralForms = Partial<Record<Intl.LDMLPluralRule, string>>;
|
|
|
23
23
|
/**
|
|
24
24
|
* A host may supply plural forms for any key, or collapse any key to one string.
|
|
25
25
|
*
|
|
26
|
-
* Which keys `en.json` ships forms for is a
|
|
26
|
+
* Which keys `en.json` ships forms for is a judgment about English, so it does
|
|
27
27
|
* not constrain a translator whose language divides them differently.
|
|
28
28
|
*/
|
|
29
29
|
export type ModulesTranslations = Record<ModulesTranslationKey, PluralForms | string>;
|
|
@@ -51,7 +51,7 @@ export interface ModulesI18nProviderProps {
|
|
|
51
51
|
children: ReactNode;
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
|
-
* Supplies the host's
|
|
54
|
+
* Supplies the host's catalog and locale.
|
|
55
55
|
*
|
|
56
56
|
* Optional — without it the package renders English, which is what makes the seam
|
|
57
57
|
* adoptable incrementally.
|