@instructure/platform-modules 0.3.0 → 0.4.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/dist/adapters/canvasGraphql/index.d.ts +7 -33
- package/dist/adapters/canvasGraphql/index.d.ts.map +1 -1
- package/dist/adapters/canvasGraphql/normalize.d.ts +44 -186
- package/dist/adapters/canvasGraphql/normalize.d.ts.map +1 -1
- package/dist/adapters/canvasGraphql/queries.d.ts +8 -36
- package/dist/adapters/canvasGraphql/queries.d.ts.map +1 -1
- package/dist/adapters/inMemory.d.ts +1 -25
- package/dist/adapters/inMemory.d.ts.map +1 -1
- package/dist/adapters/limits.d.ts +17 -74
- package/dist/adapters/limits.d.ts.map +1 -1
- package/dist/adapters/types.d.ts +10 -40
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/cache/invalidate.d.ts +0 -23
- package/dist/cache/invalidate.d.ts.map +1 -1
- package/dist/cache/keys.d.ts +2 -43
- package/dist/cache/keys.d.ts.map +1 -1
- package/dist/components/FilterChips.d.ts +4 -10
- package/dist/components/FilterChips.d.ts.map +1 -1
- package/dist/components/ModuleCard.d.ts +10 -25
- package/dist/components/ModuleCard.d.ts.map +1 -1
- package/dist/components/ModuleCard.stories.d.ts +15 -0
- package/dist/components/ModuleCard.stories.d.ts.map +1 -1
- package/dist/components/ModuleItemRow.d.ts.map +1 -1
- package/dist/components/ModuleNumberBadge.d.ts.map +1 -1
- package/dist/components/ModulesList.d.ts +2 -23
- package/dist/components/ModulesList.d.ts.map +1 -1
- package/dist/components/ModulesList.stories.d.ts +22 -81
- package/dist/components/ModulesList.stories.d.ts.map +1 -1
- package/dist/components/StatusPill.d.ts +0 -3
- 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 +26 -43
- package/dist/components/labels.d.ts.map +1 -1
- package/dist/config/context.d.ts +0 -1
- package/dist/config/context.d.ts.map +1 -1
- package/dist/config/registry.d.ts +5 -13
- package/dist/config/registry.d.ts.map +1 -1
- package/dist/config/types.d.ts +0 -3
- package/dist/config/types.d.ts.map +1 -1
- package/dist/fixtures/generate.d.ts +6 -17
- 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 +7 -32
- package/dist/fixtures/scenarios.d.ts.map +1 -1
- package/dist/hooks/constants.d.ts +4 -21
- package/dist/hooks/constants.d.ts.map +1 -1
- package/dist/hooks/queryOptions.d.ts +3 -24
- package/dist/hooks/queryOptions.d.ts.map +1 -1
- package/dist/hooks/useItemsMode.d.ts +3 -52
- package/dist/hooks/useItemsMode.d.ts.map +1 -1
- package/dist/hooks/useModuleItemQueries.d.ts +0 -38
- package/dist/hooks/useModuleItemQueries.d.ts.map +1 -1
- package/dist/hooks/useModulesPageData.d.ts +3 -29
- package/dist/hooks/useModulesPageData.d.ts.map +1 -1
- package/dist/i18n.d.ts +13 -20
- package/dist/i18n.d.ts.map +1 -1
- package/dist/index.d.ts +3 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1223 -1076
- package/dist/types/domain.d.ts +25 -80
- package/dist/types/domain.d.ts.map +1 -1
- package/dist/types/enums.d.ts +10 -41
- package/dist/types/enums.d.ts.map +1 -1
- package/dist/types/extensions.d.ts +0 -21
- package/dist/types/extensions.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/schemas.d.ts +5 -26
- package/dist/types/schemas.d.ts.map +1 -1
- package/locales/en.json +7 -7
- package/package.json +22 -19
|
@@ -1,86 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
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.
|
|
2
|
+
* Canvas REST *refuses* to inline a module over `Api::MAX_PER_PAGE` — the `items` key is
|
|
3
|
+
* simply absent and a client cannot opt out. Canvas GraphQL has no such rule; this package
|
|
4
|
+
* applies the same 100 as policy so both transports fall back at the same point.
|
|
48
5
|
*/
|
|
49
6
|
export declare const INLINE_ITEM_LIMIT = 100;
|
|
50
7
|
/**
|
|
51
8
|
* Ceiling on `pageSize × inlineItemsFirst` for a single inline request.
|
|
52
9
|
*
|
|
53
|
-
* Canvas
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
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
|
|
10
|
+
* Canvas's GraphQL complexity analyzer rejects anything over 375,000, and charges
|
|
11
|
+
* the **shape of the request, not the size of the result** — a 13-item course is
|
|
12
|
+
* refused as readily as a 13,000-item one. Measured against a real Canvas
|
|
13
|
+
* (`/api/graphql`, Aug 2026):
|
|
67
14
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* 25×100 does not.
|
|
15
|
+
* 100 × 100 1,512,106 rejected 100 × 20 accepted
|
|
16
|
+
* 100 × 50 757,106 rejected 25 × 100 378,031 rejected, barely
|
|
17
|
+
* 100 × 25 379,606 rejected 10 × 100 accepted
|
|
72
18
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
19
|
+
* That is ~151 per requested item node, so 375,000/151 ≈ 2,483 is the real
|
|
20
|
+
* ceiling and this is the round number under it. A product rather than two caps
|
|
21
|
+
* because the analyzer multiplies: 100×20 and 10×100 fit, 25×100 does not.
|
|
76
22
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
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.
|
|
23
|
+
* It lives here rather than in the GraphQL adapter so the transport-agnostic
|
|
24
|
+
* `hooks/` layer can default to it without importing `canvasGraphql` — which
|
|
25
|
+
* would drag `queries.ts` and its two module-scope `gql` parses into any bundle
|
|
26
|
+
* that only wanted the in-memory adapter.
|
|
84
27
|
*/
|
|
85
28
|
export declare const INLINE_QUERY_NODE_BUDGET = 2000;
|
|
86
29
|
//# 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;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,MAAM,CAAA;AAEpC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,wBAAwB,OAAO,CAAA"}
|
package/dist/adapters/types.d.ts
CHANGED
|
@@ -1,41 +1,16 @@
|
|
|
1
1
|
import { ModuleItemsPage, ModulesPage } from '../types/domain';
|
|
2
|
-
/**
|
|
3
|
-
* The seam between this package and a host's transport.
|
|
4
|
-
*
|
|
5
|
-
* An adapter owns exactly three things: how a request is made, what fields it
|
|
6
|
-
* asks for, and how the response becomes the domain model. It owns nothing
|
|
7
|
-
* about caching, pagination policy, or React — those live in the hooks, so
|
|
8
|
-
* that swapping GraphQL for REST changes one file and no behavior.
|
|
9
|
-
*
|
|
10
|
-
* Contract every adapter must honor:
|
|
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.
|
|
21
|
-
*/
|
|
22
2
|
export interface ModulesDataAdapter {
|
|
23
3
|
listModules(args: ListModulesArgs): Promise<ModulesPage>;
|
|
24
4
|
listModuleItems(args: ListModuleItemsArgs): Promise<ModuleItemsPage>;
|
|
25
5
|
/**
|
|
26
|
-
* The largest `modules × itemsPerModule` product this transport
|
|
27
|
-
*
|
|
6
|
+
* The largest `modules × itemsPerModule` product this transport accepts in one
|
|
7
|
+
* inline request, or `undefined` for "no limit of my own".
|
|
28
8
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
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.
|
|
9
|
+
* Declared by the transport rather than assumed by the hooks, because the
|
|
10
|
+
* ceilings have different causes — GraphQL query complexity, REST response
|
|
11
|
+
* size, none at all for the in-memory double. `resolveItemsMode` falls back to
|
|
12
|
+
* the GraphQL budget when this is unset: guessing low costs one request per
|
|
13
|
+
* opened module, guessing high gets the query rejected outright.
|
|
39
14
|
*/
|
|
40
15
|
readonly inlineNodeBudget?: number;
|
|
41
16
|
}
|
|
@@ -47,14 +22,9 @@ export interface ListModulesArgs {
|
|
|
47
22
|
/**
|
|
48
23
|
* Ask the server to inline each module's items in the same round trip.
|
|
49
24
|
*
|
|
50
|
-
* A request, not a guarantee
|
|
51
|
-
*
|
|
52
|
-
*
|
|
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.
|
|
25
|
+
* A request, not a guarantee — @see INLINE_ITEM_LIMIT. An adapter must report an
|
|
26
|
+
* accurate `itemCount` either way, and leave `items` **undefined** for a module
|
|
27
|
+
* it did not inline, never `[]`.
|
|
58
28
|
*/
|
|
59
29
|
includeItems: boolean;
|
|
60
30
|
/**
|
|
@@ -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;AAKnE,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;;;;;;;;;OASG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;;OAMG;IACH,YAAY,EAAE,OAAO,CAAA;IACrB;;;;;;;OAOG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;;OAOG;IACH,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,28 +1,5 @@
|
|
|
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
3
|
/**
|
|
27
4
|
* One module's items. Use after reordering, adding, or deleting items.
|
|
28
5
|
*
|
|
@@ -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;
|
|
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;AAKf;;;;;;;GAOG;AACH,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;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,qBAAqB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;;;;;GAMG;AACH,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,11 @@
|
|
|
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
|
+
/** A teacher sees unpublished content a student does not; the two must not share a key. */
|
|
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;
|
|
36
7
|
}
|
|
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
|
-
*/
|
|
8
|
+
/** `pageSize` partitions because two consumers at different sizes cannot share one `InfiniteData`. */
|
|
50
9
|
export interface ModuleItemsKeyOptions {
|
|
51
10
|
view?: ModulesView;
|
|
52
11
|
pageSize?: number;
|
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,2FAA2F;AAC3F,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;CACvB;AAED,sGAAsG;AACtG,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;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC,kBAAkB,EAAE,MAAM,EAAE,MAAM,CAAC,CAEjG;AAED;;;;;;GAMG;AACH,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,15 @@
|
|
|
1
1
|
import { ReactElement } from 'react';
|
|
2
2
|
import { ModulesFilterId } from './labels';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* A toggle group, not tabs: the design draws independent Buttons with nothing tying the
|
|
5
|
+
* selection to a panel, so `role="group"` + `aria-pressed` (FOUND-355).
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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.
|
|
7
|
+
* Selected is `primary`, not the mock's tinted `secondary` — the mock's two fills sit 1.25:1
|
|
8
|
+
* apart where WCAG 1.4.11 wants 3:1, and its blues come from InstUI Button v2.
|
|
14
9
|
*/
|
|
15
10
|
export interface FilterChipsProps {
|
|
16
11
|
value: ModulesFilterId;
|
|
17
12
|
onChange: (filter: ModulesFilterId) => void;
|
|
18
13
|
}
|
|
19
|
-
/** @see FilterChipsProps */
|
|
20
14
|
export declare function FilterChips({ value, onChange }: FilterChipsProps): ReactElement;
|
|
21
15
|
//# 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;;;;;;GAMG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,eAAe,CAAA;IACtB,QAAQ,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAA;CAC5C;AAED,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,gBAAgB,GAAG,YAAY,CAmD/E"}
|
|
@@ -1,15 +1,8 @@
|
|
|
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;
|
|
@@ -17,28 +10,20 @@ export interface ModuleCardProps {
|
|
|
17
10
|
/** The hook's per-module item state. Only read when `expanded`. */
|
|
18
11
|
itemsState: ModuleItemsState;
|
|
19
12
|
today: Date;
|
|
20
|
-
/**
|
|
13
|
+
/** Dev affordance, not host API. */
|
|
21
14
|
showDiagnostics?: boolean;
|
|
22
15
|
/** Stable reference required; see `ModuleItemNavigation`. */
|
|
23
16
|
navigation?: ModuleItemNavigation;
|
|
24
|
-
/**
|
|
25
|
-
* Heading level for the module name. Defaults to `'h3'`, one below
|
|
26
|
-
* `ModulesList`'s default of `h2`.
|
|
27
|
-
*/
|
|
17
|
+
/** Defaults to `'h3'`, one below `ModulesList`'s default. */
|
|
28
18
|
headingLevel?: 'h2' | 'h3' | 'h4';
|
|
29
|
-
/**
|
|
30
|
-
* Badge text: omitted derives it from `module.position`, `null` renders no
|
|
31
|
-
* badge, a string overrides.
|
|
32
|
-
*/
|
|
19
|
+
/** Omitted derives from `module.position`; `null` renders no badge. */
|
|
33
20
|
moduleLabel?: string | null;
|
|
21
|
+
breakpoints?: Breakpoints;
|
|
34
22
|
}
|
|
23
|
+
export declare const progressBarTheme: ComponentProps<typeof ProgressBar>['themeOverride'];
|
|
35
24
|
/**
|
|
36
|
-
*
|
|
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.
|
|
25
|
+
* Only useful because `itemsState` and `onToggle` are referentially stable, so a card
|
|
26
|
+
* re-renders when *its own* module changes and not when a sibling's items arrive.
|
|
42
27
|
*/
|
|
43
28
|
export declare const ModuleCard: NamedExoticComponent<ModuleCardProps>;
|
|
44
29
|
//# 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":"AACA,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;AAa5D,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,mEAAmE;IACnE,UAAU,EAAE,gBAAgB,CAAA;IAC5B,KAAK,EAAE,IAAI,CAAA;IACX,oCAAoC;IACpC,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,oBAAoB,CAAA;IACjC,6DAA6D;IAC7D,YAAY,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACjC,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AA8CD,eAAO,MAAM,gBAAgB,EAAE,cAAc,CAAC,OAAO,WAAW,CAAC,CAAC,eAAe,CAQ/E,CAAA;AAgTF;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,oBAAoB,CAAC,eAAe,CAAwB,CAAA"}
|
|
@@ -9,4 +9,19 @@ export declare const Locked: Story;
|
|
|
9
9
|
/** A label longer than the square widens the badge instead of spilling out of it. */
|
|
10
10
|
export declare const LongLabel: Story;
|
|
11
11
|
export declare const NoBadge: Story;
|
|
12
|
+
/** A completed module: Graded, Excused and Complete on one screen. */
|
|
13
|
+
export declare const ExpandedWithStatusPills: Story;
|
|
14
|
+
/** A page, a file and an external URL: the statuses ungradable content can reach. */
|
|
15
|
+
export declare const ExpandedNonGradableItems: Story;
|
|
16
|
+
/** A locked module, expanded. */
|
|
17
|
+
export declare const ExpandedLockedModule: Story;
|
|
18
|
+
/** An untouched module, expanded: every row reads Not started. */
|
|
19
|
+
export declare const ExpandedUntouchedModule: Story;
|
|
20
|
+
export declare const ProgressNotStarted: Story;
|
|
21
|
+
export declare const ProgressPartial: Story;
|
|
22
|
+
export declare const ProgressComplete: Story;
|
|
23
|
+
export declare const ProgressNoRequirements: Story;
|
|
24
|
+
export declare const ProgressLocked: Story;
|
|
25
|
+
export declare const ProgressAbsentForTeacher: Story;
|
|
26
|
+
export declare const ProgressStacked: Story;
|
|
12
27
|
//# 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;AAItD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AA2BzC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,UAAU,CAWjC,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,qFAAqF;AACrF,eAAO,MAAM,SAAS,EAAE,KAEvB,CAAA;AAED,eAAO,MAAM,OAAO,EAAE,KAErB,CAAA;AAED,sEAAsE;AACtE,eAAO,MAAM,uBAAuB,EAAE,KAErC,CAAA;AAED,qFAAqF;AACrF,eAAO,MAAM,wBAAwB,EAAE,KAWtC,CAAA;AAED,iCAAiC;AACjC,eAAO,MAAM,oBAAoB,EAAE,KAElC,CAAA;AAED,kEAAkE;AAClE,eAAO,MAAM,uBAAuB,EAAE,KAErC,CAAA;AAkBD,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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModuleItemRow.d.ts","sourceRoot":"","sources":["../../src/components/ModuleItemRow.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAAyB,KAAK,oBAAoB,EAAqB,MAAM,OAAO,CAAA;AAC3F,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,oBAAoB,EAE1B,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"ModuleItemRow.d.ts","sourceRoot":"","sources":["../../src/components/ModuleItemRow.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAAyB,KAAK,oBAAoB,EAAqB,MAAM,OAAO,CAAA;AAC3F,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,oBAAoB,EAE1B,MAAM,UAAU,CAAA;AA6BjB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,UAAU,CAAA;IAChB,kEAAkE;IAClE,KAAK,EAAE,IAAI,CAAA;IACX,6DAA6D;IAC7D,UAAU,CAAC,EAAE,oBAAoB,CAAA;CAClC;AAmJD;;;;;;;GAOG;AACH,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,+BAA+B;IAC/B,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,
|
|
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,+BAA+B;IAC/B,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,33 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
2
|
import { UseModulesPageDataResult } from '../hooks';
|
|
3
3
|
import { ModuleItemNavigation } from '../types';
|
|
4
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
5
|
export interface ModulesRequestCounts {
|
|
24
6
|
listModules: number;
|
|
25
7
|
listModuleItems: number;
|
|
26
8
|
}
|
|
27
9
|
export interface ModulesListProps {
|
|
28
|
-
/** The whole result of `useModulesPageData`, passed straight through. */
|
|
29
10
|
data: UseModulesPageDataResult;
|
|
30
|
-
/** Course title in the header. */
|
|
31
11
|
courseName?: string;
|
|
32
12
|
/** The crumb above the title, e.g. "Math". Purely decorative. */
|
|
33
13
|
courseContext?: string;
|
|
@@ -67,6 +47,5 @@ export interface ModulesListProps {
|
|
|
67
47
|
*/
|
|
68
48
|
headingLevel?: 'h1' | 'h2' | 'h3';
|
|
69
49
|
}
|
|
70
|
-
|
|
71
|
-
export declare function ModulesList({ data, courseName, courseContext, today, requestCounts, showDiagnostics, initialFilter, navigation, as, headingLevel, }: ModulesListProps): ReactElement;
|
|
50
|
+
export declare const ModulesList: ComponentType<ModulesListProps>;
|
|
72
51
|
//# 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;AACd,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,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,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;AA4VD,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC,gBAAgB,CAET,CAAA"}
|