@instructure/platform-modules 0.3.0 → 1.0.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 +3 -2
- package/dist/adapters/canvasGraphql/index.d.ts +4 -40
- package/dist/adapters/canvasGraphql/index.d.ts.map +1 -1
- package/dist/adapters/canvasGraphql/normalize.d.ts +9 -220
- package/dist/adapters/canvasGraphql/normalize.d.ts.map +1 -1
- package/dist/adapters/canvasGraphql/queries.d.ts +7 -49
- package/dist/adapters/canvasGraphql/queries.d.ts.map +1 -1
- package/dist/adapters/inMemory.d.ts +0 -40
- package/dist/adapters/inMemory.d.ts.map +1 -1
- package/dist/adapters/limits.d.ts +3 -81
- package/dist/adapters/limits.d.ts.map +1 -1
- package/dist/adapters/types.d.ts +11 -61
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/cache/invalidate.d.ts +0 -46
- package/dist/cache/invalidate.d.ts.map +1 -1
- package/dist/cache/keys.d.ts +3 -55
- package/dist/cache/keys.d.ts.map +1 -1
- package/dist/components/FilterChips.d.ts +4 -17
- package/dist/components/FilterChips.d.ts.map +1 -1
- package/dist/components/ModuleCard.d.ts +5 -29
- package/dist/components/ModuleCard.d.ts.map +1 -1
- package/dist/components/ModuleCard.stories.d.ts +14 -1
- package/dist/components/ModuleCard.stories.d.ts.map +1 -1
- package/dist/components/ModuleItemRow.d.ts +0 -10
- package/dist/components/ModuleItemRow.d.ts.map +1 -1
- package/dist/components/ModuleNumberBadge.d.ts +0 -1
- package/dist/components/ModuleNumberBadge.d.ts.map +1 -1
- package/dist/components/ModulesList.d.ts +2 -54
- package/dist/components/ModulesList.d.ts.map +1 -1
- package/dist/components/ModulesList.stories.d.ts +11 -128
- package/dist/components/ModulesList.stories.d.ts.map +1 -1
- package/dist/components/StatusPill.d.ts +4 -6
- package/dist/components/StatusPill.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/labels.d.ts +8 -78
- package/dist/components/labels.d.ts.map +1 -1
- package/dist/components/lightThemeDecorator.d.ts +3 -0
- package/dist/components/lightThemeDecorator.d.ts.map +1 -0
- package/dist/config/base.d.ts +0 -5
- package/dist/config/base.d.ts.map +1 -1
- package/dist/config/capabilities.d.ts +8 -0
- package/dist/config/capabilities.d.ts.map +1 -0
- package/dist/config/context.d.ts +1 -2
- package/dist/config/context.d.ts.map +1 -1
- package/dist/config/filters.d.ts +15 -0
- package/dist/config/filters.d.ts.map +1 -0
- package/dist/config/formatters.d.ts +15 -0
- package/dist/config/formatters.d.ts.map +1 -0
- package/dist/config/index.d.ts +9 -4
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/itemMeta.d.ts +5 -0
- package/dist/config/itemMeta.d.ts.map +1 -0
- package/dist/config/itemTypes.d.ts +4 -0
- package/dist/config/itemTypes.d.ts.map +1 -0
- package/dist/config/partialModulesConfig.d.ts +0 -1
- package/dist/config/partialModulesConfig.d.ts.map +1 -1
- package/dist/config/registry.d.ts +2 -30
- package/dist/config/registry.d.ts.map +1 -1
- package/dist/config/resolve.d.ts +0 -4
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/schemas.d.ts +37 -7
- package/dist/config/schemas.d.ts.map +1 -1
- package/dist/config/types.d.ts +8 -14
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/useFormatters.d.ts +10 -0
- package/dist/config/useFormatters.d.ts.map +1 -0
- package/dist/fixtures/generate.d.ts +1 -37
- package/dist/fixtures/generate.d.ts.map +1 -1
- package/dist/fixtures/index.d.ts +1 -1
- package/dist/fixtures/index.d.ts.map +1 -1
- package/dist/fixtures/scenarios.d.ts +4 -34
- package/dist/fixtures/scenarios.d.ts.map +1 -1
- package/dist/hooks/constants.d.ts +6 -40
- package/dist/hooks/constants.d.ts.map +1 -1
- package/dist/hooks/queryOptions.d.ts +2 -26
- package/dist/hooks/queryOptions.d.ts.map +1 -1
- package/dist/hooks/useItemsMode.d.ts +3 -84
- package/dist/hooks/useItemsMode.d.ts.map +1 -1
- package/dist/hooks/useModuleItemQueries.d.ts +1 -45
- package/dist/hooks/useModuleItemQueries.d.ts.map +1 -1
- package/dist/hooks/useModuleItems.d.ts +0 -16
- package/dist/hooks/useModuleItems.d.ts.map +1 -1
- package/dist/hooks/useModules.d.ts +3 -24
- package/dist/hooks/useModules.d.ts.map +1 -1
- package/dist/hooks/useModulesPageData.d.ts +9 -33
- package/dist/hooks/useModulesPageData.d.ts.map +1 -1
- package/dist/i18n.d.ts +8 -45
- package/dist/i18n.d.ts.map +1 -1
- package/dist/index.d.ts +5 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1874 -1344
- package/dist/types/domain.d.ts +9 -87
- package/dist/types/domain.d.ts.map +1 -1
- package/dist/types/enums.d.ts +5 -58
- package/dist/types/enums.d.ts.map +1 -1
- package/dist/types/extensions.d.ts +0 -43
- package/dist/types/extensions.d.ts.map +1 -1
- package/dist/types/filterClause.d.ts +18 -0
- package/dist/types/filterClause.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/navigation.d.ts +0 -6
- package/dist/types/navigation.d.ts.map +1 -1
- package/dist/types/schemas.d.ts +2 -28
- package/dist/types/schemas.d.ts.map +1 -1
- package/locales/en.json +20 -9
- package/package.json +35 -31
|
@@ -1,86 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The transport limits both adapters are bound by, defined once.
|
|
3
|
-
*
|
|
4
|
-
* ## What "inlining" means
|
|
5
|
-
*
|
|
6
|
-
* A modules page needs two things: the list of modules, and the items inside each
|
|
7
|
-
* module. There are two ways to get them.
|
|
8
|
-
*
|
|
9
|
-
* **Inlined** — ask for the items *in the same request as the module list*, nested
|
|
10
|
-
* under each module. One round trip for the whole page. On REST that is
|
|
11
|
-
* `?include[]=items`; on GraphQL it is the nested `moduleItemsConnection`. Cheap
|
|
12
|
-
* in requests, and the response grows with the total number of items in the
|
|
13
|
-
* course.
|
|
14
|
-
*
|
|
15
|
-
* **On demand** — ask for the module list alone, then fetch a module's items in a
|
|
16
|
-
* separate request when the user expands it. The first paint costs one request
|
|
17
|
-
* whatever the course size, and each module the user opens costs one more.
|
|
18
|
-
*
|
|
19
|
-
* Neither is right in general: inlining wins on a small course, on-demand wins on
|
|
20
|
-
* a large one, which is why `itemsMode: 'auto'` measures the course and picks.
|
|
21
|
-
* "Inlined" always describes *where the items came from*, never whether they were
|
|
22
|
-
* fetched at all — a module with `items: undefined` was not inlined, and a module
|
|
23
|
-
* with `items: []` was inlined and is genuinely empty.
|
|
24
|
-
*
|
|
25
|
-
* ## Why the ceiling is 100
|
|
26
|
-
*
|
|
27
|
-
* Above this many items in a single module, inlining stops being worthwhile — and
|
|
28
|
-
* on one transport it stops being possible. The two differ, and conflating them is
|
|
29
|
-
* easy:
|
|
30
|
-
*
|
|
31
|
-
* - **REST refuses outright.** `lib/api/v1/context_module.rb` omits the `items`
|
|
32
|
-
* key entirely for any module with more than `Api::MAX_PER_PAGE` (100) items.
|
|
33
|
-
* Server-side; a client cannot opt out.
|
|
34
|
-
* - **GraphQL has no per-module rule.** `moduleItemsConnection` is an ordinary
|
|
35
|
-
* Relay connection, and nothing in `app/graphql/types/module_type.rb` caps it.
|
|
36
|
-
*
|
|
37
|
-
* It would be wrong to conclude GraphQL will inline anything you ask for, though.
|
|
38
|
-
* Canvas runs a query-complexity analyzer, and it charges for the *shape of the
|
|
39
|
-
* request* rather than the size of the result: `first: 100, itemsFirst: 100`
|
|
40
|
-
* scores ~1.5M against a 375,000 ceiling and is rejected outright, even on a
|
|
41
|
-
* course holding thirteen items. So the ceiling is real on both transports — just
|
|
42
|
-
* enforced differently, and on different things. See `INLINE_QUERY_NODE_BUDGET`
|
|
43
|
-
* for the measurements.
|
|
44
|
-
*
|
|
45
|
-
* The GraphQL adapter therefore applies this same 100 as a deliberate *policy*,
|
|
46
|
-
* so both transports fall back to a per-module fetch at the same point and the
|
|
47
|
-
* hooks see one behavior rather than two.
|
|
48
|
-
*/
|
|
1
|
+
/** Canvas REST omits the `items` key for a module over `Api::MAX_PER_PAGE`. */
|
|
49
2
|
export declare const INLINE_ITEM_LIMIT = 100;
|
|
50
3
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* Canvas runs a GraphQL complexity analyzer and rejects anything over 375,000.
|
|
54
|
-
* Complexity is charged on the **shape of the request, not the size of the
|
|
55
|
-
* result** — so a course with 13 items is rejected just as readily as one with
|
|
56
|
-
* 13,000 if the query asks for `first: 100, itemsFirst: 100`.
|
|
57
|
-
*
|
|
58
|
-
* Measured against a real Canvas (`/api/graphql`, this document, Aug 2026):
|
|
59
|
-
*
|
|
60
|
-
* first × itemsFirst complexity verdict
|
|
61
|
-
* 100 × 100 1,512,106 rejected
|
|
62
|
-
* 100 × 50 757,106 rejected
|
|
63
|
-
* 100 × 25 379,606 rejected, barely
|
|
64
|
-
* 100 × 20 — accepted
|
|
65
|
-
* 25 × 100 378,031 rejected, barely
|
|
66
|
-
* 10 × 100 — accepted
|
|
67
|
-
*
|
|
68
|
-
* That is ~151 per requested item node, so the budget is the largest round
|
|
69
|
-
* product comfortably under 375,000/151 ≈ 2,483. Kept as a product rather than
|
|
70
|
-
* two separate caps because the analyzer multiplies: 100×20 and 10×100 both fit,
|
|
71
|
-
* 25×100 does not.
|
|
72
|
-
*
|
|
73
|
-
* If a page genuinely needs more than this, it is not an inline page — the
|
|
74
|
-
* request is split and the items fetched on demand, which is what
|
|
75
|
-
* `resolveItemsMode` is for.
|
|
76
|
-
*
|
|
77
|
-
* This is a GraphQL fact, and it lives here rather than in the GraphQL adapter
|
|
78
|
-
* for two reasons. It is the *default* the hooks assume when an adapter declines
|
|
79
|
-
* to declare its own (`ModulesDataAdapter.inlineNodeBudget`), and importing it
|
|
80
|
-
* from `adapters/canvasGraphql` was making the transport-agnostic `hooks/` layer
|
|
81
|
-
* depend on one specific transport — which also dragged `queries.ts` and its two
|
|
82
|
-
* module-scope `gql` parses into any bundle that only wanted the in-memory
|
|
83
|
-
* adapter.
|
|
4
|
+
* Canvas GraphQL refuses a request scoring over 375,000 on its complexity analyzer.
|
|
5
|
+
* Measured against `/api/graphql`: ~151 per requested item node, so 2,483 is the true ceiling.
|
|
84
6
|
*/
|
|
85
7
|
export declare const INLINE_QUERY_NODE_BUDGET = 2000;
|
|
86
8
|
//# sourceMappingURL=limits.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/adapters/limits.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/adapters/limits.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,eAAO,MAAM,iBAAiB,MAAM,CAAA;AAEpC;;;GAGG;AACH,eAAO,MAAM,wBAAwB,OAAO,CAAA"}
|
package/dist/adapters/types.d.ts
CHANGED
|
@@ -1,79 +1,29 @@
|
|
|
1
1
|
import { ModuleItemsPage, ModulesPage } from '../types/domain';
|
|
2
|
+
import { FilterCapabilities, FilterClause } from '../types/filterClause';
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
+
* Five obligations an adapter must meet:
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* - **Return a real `pageInfo`.** The GraphQL adapter passes through
|
|
13
|
-
* `endCursor`; the REST adapter derives it from the `Link` header. An
|
|
14
|
-
* adapter that hardcodes `hasNextPage: false` silently truncates, which is
|
|
15
|
-
* the live bug in Canvas Career's modules path today.
|
|
16
|
-
* - **Honor `signal`.** Collapsing a module aborts its in-flight request.
|
|
17
|
-
* - **Never invent a cursor.** Pass back what the server gave you; do not
|
|
18
|
-
* synthesize offsets client-side.
|
|
19
|
-
* - **Normalize fully.** Output must satisfy the Zod schemas. No transport
|
|
20
|
-
* detail (`_id`, `quiz_lti`, snake_case) may reach a caller.
|
|
6
|
+
* 1. Return the transport's real `pageInfo`. GraphQL: `endCursor`. REST: the parsed `Link` header.
|
|
7
|
+
* 2. Never synthesize a cursor.
|
|
8
|
+
* 3. Abort on the supplied `AbortSignal`.
|
|
9
|
+
* 4. Normalize fully. No transport detail reaches a caller.
|
|
10
|
+
* 5. Honor `ListModulesArgs.filter`, or throw. Serving a clause `capabilities` does not declare
|
|
11
|
+
* issues a cursor against the wrong result set, so every page after it is wrong too.
|
|
21
12
|
*/
|
|
22
13
|
export interface ModulesDataAdapter {
|
|
23
14
|
listModules(args: ListModulesArgs): Promise<ModulesPage>;
|
|
24
15
|
listModuleItems(args: ListModuleItemsArgs): Promise<ModuleItemsPage>;
|
|
25
|
-
/**
|
|
26
|
-
* The largest `modules × itemsPerModule` product this transport will accept in
|
|
27
|
-
* one inline request, or `undefined` for "no transport limit of my own".
|
|
28
|
-
*
|
|
29
|
-
* The transport declares its own ceiling rather than the hooks assuming one.
|
|
30
|
-
* Canvas GraphQL has a complexity analyzer that rejects the *shape* of a large
|
|
31
|
-
* inline query (@see INLINE_QUERY_NODE_BUDGET); the in-memory double has no
|
|
32
|
-
* such constraint; REST will have a different one again, bounded by
|
|
33
|
-
* `Api::MAX_PER_PAGE` and response size rather than by query complexity.
|
|
34
|
-
*
|
|
35
|
-
* `resolveItemsMode` reads this to decide whether an inline page is deliverable.
|
|
36
|
-
* When it is `undefined` the hook falls back to the GraphQL budget, which is
|
|
37
|
-
* the conservative choice: guessing too low costs one extra request per opened
|
|
38
|
-
* module, guessing too high gets the whole query rejected.
|
|
39
|
-
*/
|
|
40
16
|
readonly inlineNodeBudget?: number;
|
|
17
|
+
readonly capabilities?: FilterCapabilities;
|
|
41
18
|
}
|
|
42
19
|
export interface ListModulesArgs {
|
|
43
20
|
courseId: string;
|
|
44
|
-
/** `null`/omitted requests the first page. */
|
|
45
21
|
cursor?: string | null;
|
|
46
22
|
pageSize: number;
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
*
|
|
50
|
-
* A request, not a guarantee. Canvas REST drops the `items` key for any module
|
|
51
|
-
* over `Api::MAX_PER_PAGE` (100) items; the GraphQL path has no such server
|
|
52
|
-
* rule but this package applies the same ceiling on purpose, so both transports
|
|
53
|
-
* behave alike. Either way an adapter must report an accurate `itemCount` and
|
|
54
|
-
* leave `items` **undefined** for a module it did not inline, never `[]`.
|
|
55
|
-
*
|
|
56
|
-
* @see INLINE_ITEM_LIMIT in `adapters/limits.ts` for why the number is 100 and
|
|
57
|
-
* which half of it Canvas actually enforces.
|
|
58
|
-
*/
|
|
23
|
+
/** Only ever a clause `capabilities` admits. Throw on anything else. */
|
|
24
|
+
filter?: FilterClause;
|
|
59
25
|
includeItems: boolean;
|
|
60
|
-
/**
|
|
61
|
-
* How many items to request per module when `includeItems` is true.
|
|
62
|
-
*
|
|
63
|
-
* Omit to let the adapter use its own ceiling. Supply it when the caller has
|
|
64
|
-
* *measured* what the page needs — `useModulesPageData` does, from the `auto`
|
|
65
|
-
* probe — because a transport may charge for what the query asks for rather
|
|
66
|
-
* than for what exists. @see INLINE_QUERY_NODE_BUDGET
|
|
67
|
-
*/
|
|
68
26
|
inlineItemsFirst?: number;
|
|
69
|
-
/**
|
|
70
|
-
* How many modules to request when inlining.
|
|
71
|
-
*
|
|
72
|
-
* Omit to use `pageSize`. Supply it when the caller has measured that page 1 is
|
|
73
|
-
* the whole list, because the complexity budget is charged on
|
|
74
|
-
* `first x inlineItemsFirst` — asking for 100 modules when the course has 2 is
|
|
75
|
-
* what forces `inlineItemsFirst` to be clamped below what the page needs.
|
|
76
|
-
*/
|
|
77
27
|
inlineFirst?: number;
|
|
78
28
|
signal?: AbortSignal;
|
|
79
29
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AACnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAE7E;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IACjC,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IACxD,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IACpE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,YAAY,CAAC,EAAE,kBAAkB,CAAA;CAC3C;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,wEAAwE;IACxE,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB,YAAY,EAAE,OAAO,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB"}
|
|
@@ -1,52 +1,6 @@
|
|
|
1
1
|
import { QueryClient } from '@tanstack/react-query';
|
|
2
2
|
import { ModuleItemsKeyOptions, ModulesListKeyOptions } from './keys';
|
|
3
|
-
/**
|
|
4
|
-
* Invalidation helpers.
|
|
5
|
-
*
|
|
6
|
-
* ## What is deliberately missing
|
|
7
|
-
*
|
|
8
|
-
* There is no `invalidateOnExpand` / `invalidateOnCollapse`, and there must
|
|
9
|
-
* never be one. **Expanding or collapsing a module invalidates nothing.**
|
|
10
|
-
*
|
|
11
|
-
* Expansion is UI state. It says which rows are visible; it says nothing about
|
|
12
|
-
* whether the server's copy of the data changed. Canvas's modules page ties the
|
|
13
|
-
* two together, so every collapse invalidates the module list, every
|
|
14
|
-
* invalidation re-walks every page that has been loaded, and a course with
|
|
15
|
-
* thirty modules re-fetches the world each time a teacher tidies the screen.
|
|
16
|
-
* That is the refetch loop this package exists to not have.
|
|
17
|
-
*
|
|
18
|
-
* The equivalents here:
|
|
19
|
-
* - collapse → cancel that module's in-flight item request (an abort, not an
|
|
20
|
-
* invalidation — see `useModulesPageData`), and leave the cached pages alone
|
|
21
|
-
* - re-expand → a cache hit, no request
|
|
22
|
-
*
|
|
23
|
-
* Invalidate when the *data* changed: a mutation, a websocket nudge, an
|
|
24
|
-
* explicit user refresh. Not when a disclosure arrow moved.
|
|
25
|
-
*/
|
|
26
|
-
/**
|
|
27
|
-
* One module's items. Use after reordering, adding, or deleting items.
|
|
28
|
-
*
|
|
29
|
-
* Omit `opts` — the default — to hit every variant of that module's items, which
|
|
30
|
-
* is what a mutation wants: adding an item changes the module for the student
|
|
31
|
-
* view and the teacher view alike, at every page size any consumer rendered
|
|
32
|
-
* with. Pass `opts` only to target the exact query one hook instance holds.
|
|
33
|
-
*/
|
|
34
3
|
export declare function invalidateModuleItems(queryClient: QueryClient, courseId: string, moduleId: string, opts?: ModuleItemsKeyOptions): Promise<void>;
|
|
35
|
-
/**
|
|
36
|
-
* The module list for a course.
|
|
37
|
-
*
|
|
38
|
-
* Omit `opts` to hit every list variant (all page sizes, both views, inline and
|
|
39
|
-
* on-demand) — which is almost always what you want, since a mutation that adds
|
|
40
|
-
* or removes a module invalidates all of them. Pass `opts` only to target the
|
|
41
|
-
* exact query a specific hook instance is rendering.
|
|
42
|
-
*/
|
|
43
4
|
export declare function invalidateModuleList(queryClient: QueryClient, courseId: string, opts?: ModulesListKeyOptions): Promise<void>;
|
|
44
|
-
/**
|
|
45
|
-
* Everything for a course: the list and every module's items.
|
|
46
|
-
*
|
|
47
|
-
* The blunt instrument. Reasonable after a bulk operation (publish all, import
|
|
48
|
-
* a course package); wasteful after a single-item edit, which should use
|
|
49
|
-
* `invalidateModuleItems`.
|
|
50
|
-
*/
|
|
51
5
|
export declare function invalidateCourse(queryClient: QueryClient, courseId: string): Promise<void>;
|
|
52
6
|
//# sourceMappingURL=invalidate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invalidate.d.ts","sourceRoot":"","sources":["../../src/cache/invalidate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAIL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,QAAQ,CAAA;AAEf
|
|
1
|
+
{"version":3,"file":"invalidate.d.ts","sourceRoot":"","sources":["../../src/cache/invalidate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAIL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,QAAQ,CAAA;AAEf,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,qBAAqB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,qBAAqB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1F"}
|
package/dist/cache/keys.d.ts
CHANGED
|
@@ -1,52 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
* Query keys for the modules page.
|
|
3
|
-
*
|
|
4
|
-
* One factory, one shape, one place to look when you need to know what a given
|
|
5
|
-
* invalidation will hit. Every key is a `readonly` tuple so TanStack Query keeps
|
|
6
|
-
* the key type narrow instead of widening it to `unknown[]`, and so a typo in a
|
|
7
|
-
* literal segment is a compile error rather than a silent cache miss.
|
|
8
|
-
*
|
|
9
|
-
* The hierarchy is deliberate — each level is a prefix of the next, which is
|
|
10
|
-
* what makes `invalidateCourse` able to reach every query for a course without
|
|
11
|
-
* enumerating them:
|
|
12
|
-
*
|
|
13
|
-
* ['platform-modules']
|
|
14
|
-
* ['platform-modules', courseId]
|
|
15
|
-
* ['platform-modules', courseId, 'list', opts]
|
|
16
|
-
* ['platform-modules', courseId, 'module', moduleId, 'items', opts]
|
|
17
|
-
*/
|
|
18
|
-
/**
|
|
19
|
-
* Which Canvas audience the page is rendered for.
|
|
20
|
-
*
|
|
21
|
-
* It is not passed to the adapter — a host configures its adapter for the
|
|
22
|
-
* current user already — but it *is* part of every key, because a teacher sees
|
|
23
|
-
* unpublished content a student does not. Two views must never share a cache
|
|
24
|
-
* entry.
|
|
25
|
-
*/
|
|
1
|
+
import { FilterClause } from '../types/filterClause';
|
|
26
2
|
export type ModulesView = 'student' | 'teacher';
|
|
27
|
-
/**
|
|
28
|
-
* Everything that changes what a list request returns, and therefore has to
|
|
29
|
-
* partition the cache. `includeItems` is here because the inline and on-demand
|
|
30
|
-
* shapes of the same page are genuinely different payloads.
|
|
31
|
-
*/
|
|
32
3
|
export interface ModulesListKeyOptions {
|
|
33
4
|
view?: ModulesView;
|
|
34
5
|
pageSize?: number;
|
|
35
6
|
includeItems?: boolean;
|
|
7
|
+
/** The clause partitions, not the chip. Chips the server never saw share one entry. */
|
|
8
|
+
filter?: FilterClause;
|
|
36
9
|
}
|
|
37
|
-
/**
|
|
38
|
-
* The items equivalent, and it exists for the same two reasons the list one does.
|
|
39
|
-
*
|
|
40
|
-
* `view` because `published` is a per-*item* field, so the teacher/student
|
|
41
|
-
* argument above applies to items verbatim: a teacher's page of items includes
|
|
42
|
-
* unpublished rows a student's does not.
|
|
43
|
-
*
|
|
44
|
-
* `pageSize` because these are infinite queries. The cache entry is an
|
|
45
|
-
* `InfiniteData` whose `pages` were each fetched at some size; two consumers
|
|
46
|
-
* rendering the same module with different `itemPageSize` would otherwise share
|
|
47
|
-
* one entry whose pages were fetched at mixed sizes, and neither could say what
|
|
48
|
-
* `pages[n]` contains.
|
|
49
|
-
*/
|
|
50
10
|
export interface ModuleItemsKeyOptions {
|
|
51
11
|
view?: ModulesView;
|
|
52
12
|
pageSize?: number;
|
|
@@ -69,18 +29,6 @@ export interface ModulesKeyFactory {
|
|
|
69
29
|
items(courseId: string, moduleId: string, opts?: ModuleItemsKeyOptions): ModuleItemsKey;
|
|
70
30
|
}
|
|
71
31
|
export declare const modulesKeys: ModulesKeyFactory;
|
|
72
|
-
/**
|
|
73
|
-
* The prefix shared by every list key for a course, regardless of `opts`.
|
|
74
|
-
* Used to invalidate "the module list" without knowing which page size or view
|
|
75
|
-
* the caller happened to render with.
|
|
76
|
-
*/
|
|
77
32
|
export declare function modulesListPrefix(courseId: string): readonly ['platform-modules', string, 'list'];
|
|
78
|
-
/**
|
|
79
|
-
* The prefix shared by every items key for one module, regardless of `opts`.
|
|
80
|
-
*
|
|
81
|
-
* This is the one to reach for when acting on "that module's items" without
|
|
82
|
-
* knowing which view or page size rendered them — invalidating after a mutation,
|
|
83
|
-
* or canceling in flight requests on collapse.
|
|
84
|
-
*/
|
|
85
33
|
export declare function moduleItemsPrefix(courseId: string, moduleId: string): readonly ['platform-modules', string, 'module', string, 'items'];
|
|
86
34
|
//# sourceMappingURL=keys.d.ts.map
|
package/dist/cache/keys.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/cache/keys.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/cache/keys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEzD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,CAAA;AAE/C,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,uFAAuF;IACvF,MAAM,CAAC,EAAE,YAAY,CAAA;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC,kBAAkB,CAAC,CAAA;AACzD,MAAM,MAAM,gBAAgB,GAAG,SAAS,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAA;AACpE,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC,kBAAkB,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,CAAC,CAAA;AACjG,MAAM,MAAM,cAAc,GAAG,SAAS;IACpC,kBAAkB;IAClB,MAAM;IACN,QAAQ;IACR,MAAM;IACN,OAAO;IACP,qBAAqB;CACtB,CAAA;AAID,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAA;IAC3B,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAAA;IAC1C,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,qBAAqB,GAAG,cAAc,CAAA;IACpE,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,qBAAqB,GAAG,cAAc,CAAA;CACxF;AAED,eAAO,MAAM,WAAW,EAAE,iBAOzB,CAAA;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC,kBAAkB,EAAE,MAAM,EAAE,MAAM,CAAC,CAEjG;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,SAAS,CAAC,kBAAkB,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAElE"}
|
|
@@ -1,21 +1,8 @@
|
|
|
1
1
|
import { ReactElement } from 'react';
|
|
2
|
-
import { ModulesFilterId } from './labels';
|
|
3
|
-
/**
|
|
4
|
-
* The filter row: a toggle group, not tabs.
|
|
5
|
-
*
|
|
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.
|
|
14
|
-
*/
|
|
15
2
|
export interface FilterChipsProps {
|
|
16
|
-
value:
|
|
17
|
-
onChange: (filter:
|
|
3
|
+
value: string;
|
|
4
|
+
onChange: (filter: string) => void;
|
|
5
|
+
describedBy?: string;
|
|
18
6
|
}
|
|
19
|
-
|
|
20
|
-
export declare function FilterChips({ value, onChange }: FilterChipsProps): ReactElement;
|
|
7
|
+
export declare function FilterChips({ value, onChange, describedBy }: FilterChipsProps): ReactElement;
|
|
21
8
|
//# 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,
|
|
1
|
+
{"version":3,"file":"FilterChips.d.ts","sourceRoot":"","sources":["../../src/components/FilterChips.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAAkB,MAAM,OAAO,CAAA;AAIzD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,gBAAgB,GAAG,YAAY,CA4C5F"}
|
|
@@ -1,44 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Breakpoints } from '@instructure/platform-with-breakpoints';
|
|
2
|
+
import { ProgressBar } from '@instructure/ui-progress/v11_7';
|
|
3
|
+
import { ComponentProps, NamedExoticComponent } from 'react';
|
|
2
4
|
import { ModuleItemsState } from '../hooks';
|
|
3
5
|
import { Module, ModuleItemNavigation } from '../types';
|
|
4
|
-
/**
|
|
5
|
-
* One module card.
|
|
6
|
-
*
|
|
7
|
-
* Header: number badge, name, byline, status pill, expand toggle.
|
|
8
|
-
* Progress row: **only when `module.progress` exists**.
|
|
9
|
-
*
|
|
10
|
-
* Expanded body: the item rows, plus the per-module "Load more items" control
|
|
11
|
-
* whenever `hasNextPage` is true.
|
|
12
|
-
*/
|
|
13
6
|
export interface ModuleCardProps {
|
|
14
7
|
module: Module;
|
|
15
8
|
expanded: boolean;
|
|
16
9
|
onToggle: (moduleId: string) => void;
|
|
17
|
-
/** The hook's per-module item state. Only read when `expanded`. */
|
|
18
10
|
itemsState: ModuleItemsState;
|
|
19
11
|
today: Date;
|
|
20
|
-
/** Show the `inline` vs `onDemand` provenance line. Dev affordance, off by default. */
|
|
21
12
|
showDiagnostics?: boolean;
|
|
22
|
-
/** Stable reference required; see `ModuleItemNavigation`. */
|
|
23
13
|
navigation?: ModuleItemNavigation;
|
|
24
|
-
/**
|
|
25
|
-
* Heading level for the module name. Defaults to `'h3'`, one below
|
|
26
|
-
* `ModulesList`'s default of `h2`.
|
|
27
|
-
*/
|
|
28
14
|
headingLevel?: 'h2' | 'h3' | 'h4';
|
|
29
|
-
/**
|
|
30
|
-
* Badge text: omitted derives it from `module.position`, `null` renders no
|
|
31
|
-
* badge, a string overrides.
|
|
32
|
-
*/
|
|
33
15
|
moduleLabel?: string | null;
|
|
16
|
+
breakpoints?: Breakpoints;
|
|
34
17
|
}
|
|
35
|
-
|
|
36
|
-
* Memoized, which is only useful because its props are now stable.
|
|
37
|
-
*
|
|
38
|
-
* `itemsState` comes from `useModulesPageData`'s per-module cache and `onToggle`
|
|
39
|
-
* from a ref-backed `useCallback`, so a card re-renders when *its own* module
|
|
40
|
-
* changes and not when a sibling's items arrive. Both of those had to be fixed
|
|
41
|
-
* first — a `memo` over freshly-built props is pure overhead.
|
|
42
|
-
*/
|
|
18
|
+
export declare const progressBarTheme: ComponentProps<typeof ProgressBar>['themeOverride'];
|
|
43
19
|
export declare const ModuleCard: NamedExoticComponent<ModuleCardProps>;
|
|
44
20
|
//# sourceMappingURL=ModuleCard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModuleCard.d.ts","sourceRoot":"","sources":["../../src/components/ModuleCard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ModuleCard.d.ts","sourceRoot":"","sources":["../../src/components/ModuleCard.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAMzE,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA;AAI5D,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,oBAAoB,EAI1B,MAAM,OAAO,CAAA;AACd,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAQ5D,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,UAAU,EAAE,gBAAgB,CAAA;IAC5B,KAAK,EAAE,IAAI,CAAA;IACX,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,UAAU,CAAC,EAAE,oBAAoB,CAAA;IACjC,YAAY,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACjC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AA8BD,eAAO,MAAM,gBAAgB,EAAE,cAAc,CAAC,OAAO,WAAW,CAAC,CAAC,eAAe,CAQ/E,CAAA;AAsRF,eAAO,MAAM,UAAU,EAAE,oBAAoB,CAAC,eAAe,CAAwB,CAAA"}
|
|
@@ -6,7 +6,20 @@ type Story = StoryObj<typeof meta>;
|
|
|
6
6
|
export declare const Default: Story;
|
|
7
7
|
export declare const ThreeDigitNumber: Story;
|
|
8
8
|
export declare const Locked: Story;
|
|
9
|
-
/** A label longer than the square widens the badge instead of spilling out of it. */
|
|
10
9
|
export declare const LongLabel: Story;
|
|
11
10
|
export declare const NoBadge: Story;
|
|
11
|
+
export declare const ExpandedWithStatusPills: Story;
|
|
12
|
+
export declare const ExpandedNonGradableItems: Story;
|
|
13
|
+
export declare const ExpandedLockedModule: Story;
|
|
14
|
+
export declare const ExpandedUntouchedModule: Story;
|
|
15
|
+
export declare const ProgressNotStarted: Story;
|
|
16
|
+
export declare const ProgressPartial: Story;
|
|
17
|
+
export declare const ProgressComplete: Story;
|
|
18
|
+
export declare const ProgressNoRequirements: Story;
|
|
19
|
+
export declare const ProgressLocked: Story;
|
|
20
|
+
export declare const ProgressAbsentForTeacher: Story;
|
|
21
|
+
export declare const ProgressStacked: Story;
|
|
22
|
+
export declare const LongModuleName: Story;
|
|
23
|
+
export declare const LetterLabelScheme: Story;
|
|
24
|
+
export declare const NoLabelScheme: Story;
|
|
12
25
|
//# sourceMappingURL=ModuleCard.stories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModuleCard.stories.d.ts","sourceRoot":"","sources":["../../src/components/ModuleCard.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"ModuleCard.stories.d.ts","sourceRoot":"","sources":["../../src/components/ModuleCard.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAKtD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AA2BzC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,UAAU,CAYjC,CAAA;AAED,eAAe,IAAI,CAAA;AACnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAA;AAElC,eAAO,MAAM,OAAO,EAAE,KAAU,CAAA;AAEhC,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAA;AAED,eAAO,MAAM,MAAM,EAAE,KAEpB,CAAA;AAED,eAAO,MAAM,SAAS,EAAE,KAEvB,CAAA;AAED,eAAO,MAAM,OAAO,EAAE,KAErB,CAAA;AAED,eAAO,MAAM,uBAAuB,EAAE,KAErC,CAAA;AAED,eAAO,MAAM,wBAAwB,EAAE,KAWtC,CAAA;AAED,eAAO,MAAM,oBAAoB,EAAE,KAElC,CAAA;AAED,eAAO,MAAM,uBAAuB,EAAE,KAErC,CAAA;AAmBD,eAAO,MAAM,kBAAkB,EAAE,KAEhC,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,KAE7B,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAA;AAED,eAAO,MAAM,sBAAsB,EAAE,KAEpC,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAA;AAED,eAAO,MAAM,wBAAwB,EAAE,KAEtC,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,KAE7B,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,KAO5B,CAAA;AAQD,eAAO,MAAM,iBAAiB,EAAE,KAU/B,CAAA;AAED,eAAO,MAAM,aAAa,EAAE,KAM3B,CAAA"}
|
|
@@ -2,18 +2,8 @@ import { NamedExoticComponent } from 'react';
|
|
|
2
2
|
import { ModuleItem, ModuleItemNavigation } from '../types';
|
|
3
3
|
export interface ModuleItemRowProps {
|
|
4
4
|
item: ModuleItem;
|
|
5
|
-
/** Injected so relative dates ("yesterday") are deterministic. */
|
|
6
5
|
today: Date;
|
|
7
|
-
/** Stable reference required; see `ModuleItemNavigation`. */
|
|
8
6
|
navigation?: ModuleItemNavigation;
|
|
9
7
|
}
|
|
10
|
-
/**
|
|
11
|
-
* Memoized because it is the hottest component in the package.
|
|
12
|
-
*
|
|
13
|
-
* `item` is a stable reference out of the query cache and `today` is pinned per
|
|
14
|
-
* mount, so the default shallow comparison is enough. It is what stops one
|
|
15
|
-
* module's observer publishing from re-rendering every other module's rows —
|
|
16
|
-
* ~3000 of them on a 30-module course with everything expanded.
|
|
17
|
-
*/
|
|
18
8
|
export declare const ModuleItemRow: NamedExoticComponent<ModuleItemRowProps>;
|
|
19
9
|
//# sourceMappingURL=ModuleItemRow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModuleItemRow.d.ts","sourceRoot":"","sources":["../../src/components/ModuleItemRow.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ModuleItemRow.d.ts","sourceRoot":"","sources":["../../src/components/ModuleItemRow.tsx"],"names":[],"mappings":"AAOA,OAAO,EAKL,KAAK,oBAAoB,EAI1B,MAAM,OAAO,CAAA;AASd,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAmChE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,UAAU,CAAA;IAChB,KAAK,EAAE,IAAI,CAAA;IACX,UAAU,CAAC,EAAE,oBAAoB,CAAA;CAClC;AAiKD,eAAO,MAAM,aAAa,EAAE,oBAAoB,CAAC,kBAAkB,CAA2B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModuleNumberBadge.d.ts","sourceRoot":"","sources":["../../src/components/ModuleNumberBadge.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AAIzC,MAAM,WAAW,sBAAsB;IACrC
|
|
1
|
+
{"version":3,"file":"ModuleNumberBadge.d.ts","sourceRoot":"","sources":["../../src/components/ModuleNumberBadge.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AAIzC,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,MAAc,GACf,EAAE,sBAAsB,GAAG,YAAY,GAAG,IAAI,CAsB9C"}
|
|
@@ -1,72 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
2
|
import { UseModulesPageDataResult } from '../hooks';
|
|
3
3
|
import { ModuleItemNavigation } from '../types';
|
|
4
|
-
import { ModulesFilterId } from './labels';
|
|
5
|
-
/**
|
|
6
|
-
* The student modules page, approximating the Modules Foundation design.
|
|
7
|
-
*
|
|
8
|
-
* What it is: course header, a module-name search, an expand/collapse menu, the
|
|
9
|
-
* module-level filter row, and a stack of module cards.
|
|
10
|
-
*
|
|
11
|
-
* What it deliberately is not:
|
|
12
|
-
*
|
|
13
|
-
* - **No progress strip.** The `01 02 03 …` paginated bar under the filters in
|
|
14
|
-
* the mock is out of scope; the user deferred it.
|
|
15
|
-
* - **No item-level search.** See `moduleMatchesSearch`: in `onDemand` mode the
|
|
16
|
-
* items of collapsed modules are not loaded, so searching them would silently
|
|
17
|
-
* under-report. The input filters module *names* and says so on its label.
|
|
18
|
-
* Everything renderable comes from `useModulesPageData`; this component owns
|
|
19
|
-
* only view state (search text, active filter), never data. Expanding a module
|
|
20
|
-
* still invalidates nothing.
|
|
21
|
-
*/
|
|
22
|
-
/** Requests served by the adapter so far, split by operation. */
|
|
23
4
|
export interface ModulesRequestCounts {
|
|
24
5
|
listModules: number;
|
|
25
6
|
listModuleItems: number;
|
|
26
7
|
}
|
|
27
8
|
export interface ModulesListProps {
|
|
28
|
-
/** The whole result of `useModulesPageData`, passed straight through. */
|
|
29
9
|
data: UseModulesPageDataResult;
|
|
30
|
-
/** Course title in the header. */
|
|
31
10
|
courseName?: string;
|
|
32
|
-
/** The crumb above the title, e.g. "Math". Purely decorative. */
|
|
33
11
|
courseContext?: string;
|
|
34
|
-
/**
|
|
35
|
-
* "Now", injected so relative dates and the "Due this week" filter are
|
|
36
|
-
* deterministic in stories and tests. The fixtures use a fixed 2025-01-06
|
|
37
|
-
* epoch, so a story that wants sensible dates should pin this.
|
|
38
|
-
*/
|
|
39
12
|
today?: Date;
|
|
40
|
-
/**
|
|
41
|
-
* Live counts from `createInMemoryAdapter`'s `onRequest`. When supplied, a
|
|
42
|
-
* dev banner renders them. It is the most useful thing on screen for
|
|
43
|
-
* reviewing this MVP — "does this scale" as a number rather than a devtools
|
|
44
|
-
* exercise — and a host with a real adapter simply omits the prop.
|
|
45
|
-
*/
|
|
46
13
|
requestCounts?: ModulesRequestCounts;
|
|
47
|
-
/** Also show items-mode and per-module item provenance. Defaults to `requestCounts !== undefined`. */
|
|
48
14
|
showDiagnostics?: boolean;
|
|
49
|
-
/** Which chip starts active. Uncontrolled after mount — the chips own it. */
|
|
50
|
-
initialFilter?: ModulesFilterId;
|
|
51
|
-
/** Stable reference required; see `ModuleItemNavigation`. */
|
|
52
15
|
navigation?: ModuleItemNavigation;
|
|
53
|
-
/**
|
|
54
|
-
* Element for the outer container. Defaults to `'div'`.
|
|
55
|
-
*
|
|
56
|
-
* Deliberately not `'main'` by default: Canvas's own layout already ships
|
|
57
|
-
* `role="main"` (`application.html.erb:267`), so a Canvas host rendering this
|
|
58
|
-
* would get two main landmarks. A host that owns its whole page can opt in with
|
|
59
|
-
* `as="main"`.
|
|
60
|
-
*/
|
|
61
16
|
as?: 'div' | 'main' | 'section';
|
|
62
|
-
/**
|
|
63
|
-
* Heading level for the course title. Defaults to `'h2'`.
|
|
64
|
-
*
|
|
65
|
-
* Also not `h1` by default, and for the same reason: a host page usually already
|
|
66
|
-
* has one. `ModuleCard` renders one level below this.
|
|
67
|
-
*/
|
|
68
17
|
headingLevel?: 'h1' | 'h2' | 'h3';
|
|
69
18
|
}
|
|
70
|
-
|
|
71
|
-
export declare function ModulesList({ data, courseName, courseContext, today, requestCounts, showDiagnostics, initialFilter, navigation, as, headingLevel, }: ModulesListProps): ReactElement;
|
|
19
|
+
export declare const ModulesList: ComponentType<ModulesListProps>;
|
|
72
20
|
//# sourceMappingURL=ModulesList.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModulesList.d.ts","sourceRoot":"","sources":["../../src/components/ModulesList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ModulesList.d.ts","sourceRoot":"","sources":["../../src/components/ModulesList.tsx"],"names":[],"mappings":"AAYA,OAAO,EACL,KAAK,aAAa,EAOnB,MAAM,OAAO,CAAA;AAEd,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AACxD,OAAO,KAAK,EAAU,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAM5D,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,wBAAwB,CAAA;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,CAAC,EAAE,IAAI,CAAA;IACZ,aAAa,CAAC,EAAE,oBAAoB,CAAA;IACpC,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,UAAU,CAAC,EAAE,oBAAoB,CAAA;IACjC,EAAE,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,CAAA;IAC/B,YAAY,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;CAClC;AAkVD,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC,gBAAgB,CAET,CAAA"}
|