shelving 1.240.0 → 1.241.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.
@@ -336,6 +336,7 @@ function _getReturns(statement, source, jsDocReturns, name) {
336
336
  * - Members declared with the `override` modifier are skipped — the base class already documents them, so a subclass page lists only its newly-introduced API.
337
337
  * - Members declared with the `declare` modifier are skipped — they're ambient type-only re-declarations (e.g. narrowing an inherited property's type), not new API.
338
338
  * - Getters/setters fold into a single `property` element per name; a getter with no matching setter is `readonly`.
339
+ * - `static` members are labelled `static method` / `static property` so the docs site groups them in their own sections, separate from instance `method` / `property`, and their rendered signature is prefixed with the `static ` keyword.
339
340
  */
340
341
  function _getClassMembers(statement, source, className) {
341
342
  if (!ts.isClassDeclaration(statement) && !ts.isInterfaceDeclaration(statement))
@@ -355,13 +356,17 @@ function _getClassMembers(statement, source, className) {
355
356
  // Skip `declare` members — ambient type-only re-declarations (e.g. a subclass narrowing an inherited property's type), not new API.
356
357
  if (modifiers?.some(m => m.kind === ts.SyntaxKind.DeclareKeyword))
357
358
  continue;
359
+ // `static` members are grouped and labelled separately from instance members (`static method` / `static property`),
360
+ // and carry the `static ` keyword in their rendered signature.
361
+ const isStatic = modifiers?.some(m => m.kind === ts.SyntaxKind.StaticKeyword);
362
+ const staticPrefix = isStatic ? "static " : "";
358
363
  const memberJSDoc = _getJSDoc(member, source);
359
364
  const content = _buildJSDocContent(memberJSDoc?.description, memberJSDoc?.unhandled);
360
365
  const description = extractMarkdownProps(memberJSDoc?.description ?? "").description;
361
366
  if (ts.isMethodDeclaration(member) || ts.isMethodSignature(member)) {
362
367
  const params = member.parameters.map(p => p.getText(source)).join(", ");
363
368
  const ret = member.type ? member.type.getText(source) : "void";
364
- const signature = `${name}(${params}): ${ret}`;
369
+ const signature = `${staticPrefix}${name}(${params}): ${ret}`;
365
370
  const key = name;
366
371
  const existingIndex = members.findIndex(m => m.key === key);
367
372
  const existing = members[existingIndex];
@@ -380,7 +385,7 @@ function _getClassMembers(statement, source, className) {
380
385
  title: `${name}()`,
381
386
  description,
382
387
  content,
383
- kind: "method",
388
+ kind: isStatic ? "static method" : "method",
384
389
  class: className,
385
390
  signatures: [signature],
386
391
  },
@@ -398,10 +403,10 @@ function _getClassMembers(statement, source, className) {
398
403
  title: name,
399
404
  description,
400
405
  content,
401
- kind: "property",
406
+ kind: isStatic ? "static property" : "property",
402
407
  class: className,
403
408
  readonly,
404
- signatures: type ? [`${readonly ? "readonly " : ""}${name}: ${type}`] : undefined,
409
+ signatures: type ? [`${staticPrefix}${readonly ? "readonly " : ""}${name}: ${type}`] : undefined,
405
410
  },
406
411
  });
407
412
  }
@@ -418,7 +423,7 @@ function _getClassMembers(statement, source, className) {
418
423
  ...existing.props,
419
424
  // A getter + setter pair is writable — drop the read-only flag and the `readonly ` signature prefix.
420
425
  readonly: undefined,
421
- signatures: type ? [`${name}: ${type}`] : existing.props.signatures,
426
+ signatures: type ? [`${staticPrefix}${name}: ${type}`] : existing.props.signatures,
422
427
  },
423
428
  };
424
429
  }
@@ -431,10 +436,10 @@ function _getClassMembers(statement, source, className) {
431
436
  title: name,
432
437
  description,
433
438
  content,
434
- kind: "property",
439
+ kind: isStatic ? "static property" : "property",
435
440
  class: className,
436
441
  readonly: ts.isGetAccessor(member) || undefined,
437
- signatures: type ? [`${ts.isGetAccessor(member) ? "readonly " : ""}${name}: ${type}`] : undefined,
442
+ signatures: type ? [`${staticPrefix}${ts.isGetAccessor(member) ? "readonly " : ""}${name}: ${type}`] : undefined,
438
443
  },
439
444
  });
440
445
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shelving",
3
- "version": "1.240.0",
3
+ "version": "1.241.0",
4
4
  "author": "Dave Houlbrooke <dave@shax.com>",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,7 +8,7 @@ import type { UIColor } from "../style/Color.js";
8
8
  * @see https://dhoulb.github.io/shelving/ui/docs/DocumentationKind/DocumentationKindProps
9
9
  */
10
10
  export interface DocumentationKindProps extends TagProps {
11
- /** The documentation kind (e.g. `"component"`, `"function"`, `"class"`, `"interface"`, `"type"`, `"constant"`, `"method"`, `"property"`). */
11
+ /** The documentation kind (e.g. `"component"`, `"function"`, `"class"`, `"interface"`, `"type"`, `"constant"`, `"method"`, `"static method"`, `"property"`, `"static property"`). */
12
12
  readonly kind: string;
13
13
  }
14
14
  /**
@@ -12,10 +12,12 @@ const KIND_COLOR = {
12
12
  class: "purple",
13
13
  function: "blue",
14
14
  method: "blue",
15
+ "static method": "blue",
15
16
  interface: "aqua",
16
17
  type: "aqua",
17
18
  constant: "green",
18
19
  property: "yellow",
20
+ "static property": "yellow",
19
21
  };
20
22
  /**
21
23
  * Get the raw colour variant for a documented symbol's `kind`, or `undefined` for an unknown kind.
@@ -10,7 +10,7 @@ import { Row } from "../style/Flex.js";
10
10
  * @see https://dhoulb.github.io/shelving/ui/docs/DocumentationKind/DocumentationKindProps
11
11
  */
12
12
  export interface DocumentationKindProps extends TagProps {
13
- /** The documentation kind (e.g. `"component"`, `"function"`, `"class"`, `"interface"`, `"type"`, `"constant"`, `"method"`, `"property"`). */
13
+ /** The documentation kind (e.g. `"component"`, `"function"`, `"class"`, `"interface"`, `"type"`, `"constant"`, `"method"`, `"static method"`, `"property"`, `"static property"`). */
14
14
  readonly kind: string;
15
15
  }
16
16
 
@@ -25,10 +25,12 @@ const KIND_COLOR: { readonly [K in string]?: UIColor } = {
25
25
  class: "purple",
26
26
  function: "blue",
27
27
  method: "blue",
28
+ "static method": "blue",
28
29
  interface: "aqua",
29
30
  type: "aqua",
30
31
  constant: "green",
31
32
  property: "yellow",
33
+ "static property": "yellow",
32
34
  };
33
35
 
34
36
  /**
@@ -30,6 +30,8 @@ const KIND_SECTIONS = {
30
30
  interface: "Interfaces",
31
31
  type: "Types",
32
32
  constant: "Constants",
33
+ "static method": "Static methods",
34
+ "static property": "Static properties",
33
35
  method: "Methods",
34
36
  property: "Properties",
35
37
  };
@@ -41,4 +41,20 @@ describe("DocumentationPage", () => {
41
41
  expect(html).not.toContain("Functions");
42
42
  expect(html).not.toContain("Interfaces");
43
43
  });
44
+
45
+ test("groups static members into their own sections, before instance sections", () => {
46
+ const html = render(
47
+ <DocumentationPage path="/Color" name="Color" kind="class">
48
+ {[doc("from", "static method"), doc("DEFAULT", "static property"), doc("toString", "method"), doc("red", "property")]}
49
+ </DocumentationPage>,
50
+ "./Color",
51
+ );
52
+ expect(html).toContain("Static methods");
53
+ expect(html).toContain("Static properties");
54
+ expect(html).toContain("Methods");
55
+ expect(html).toContain("Properties");
56
+ // Static sections render before their instance counterparts (the `Methods` / `Properties` headings use a capital, so they don't match inside `Static methods`).
57
+ expect(html.indexOf("Static methods")).toBeLessThan(html.indexOf("Methods"));
58
+ expect(html.indexOf("Static properties")).toBeLessThan(html.indexOf("Properties"));
59
+ });
44
60
  });
@@ -33,6 +33,8 @@ const KIND_SECTIONS = {
33
33
  interface: "Interfaces",
34
34
  type: "Types",
35
35
  constant: "Constants",
36
+ "static method": "Static methods",
37
+ "static property": "Static properties",
36
38
  method: "Methods",
37
39
  property: "Properties",
38
40
  };