@storybook/web-components 11.0.0-alpha.6 → 11.0.0-alpha.7

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.
@@ -1,18 +1,18 @@
1
- import CJS_COMPAT_NODE_URL_3ov4ld79bt3 from 'node:url';
2
- import CJS_COMPAT_NODE_PATH_3ov4ld79bt3 from 'node:path';
3
- import CJS_COMPAT_NODE_MODULE_3ov4ld79bt3 from "node:module";
1
+ import CJS_COMPAT_NODE_URL_seyt09815b from 'node:url';
2
+ import CJS_COMPAT_NODE_PATH_seyt09815b from 'node:path';
3
+ import CJS_COMPAT_NODE_MODULE_seyt09815b from "node:module";
4
4
 
5
- var __filename = CJS_COMPAT_NODE_URL_3ov4ld79bt3.fileURLToPath(import.meta.url);
6
- var __dirname = CJS_COMPAT_NODE_PATH_3ov4ld79bt3.dirname(__filename);
7
- var require = CJS_COMPAT_NODE_MODULE_3ov4ld79bt3.createRequire(import.meta.url);
5
+ var __filename = CJS_COMPAT_NODE_URL_seyt09815b.fileURLToPath(import.meta.url);
6
+ var __dirname = CJS_COMPAT_NODE_PATH_seyt09815b.dirname(__filename);
7
+ var require = CJS_COMPAT_NODE_MODULE_seyt09815b.createRequire(import.meta.url);
8
8
 
9
9
  // ------------------------------------------------------------
10
10
  // end of CJS compatibility banner, injected by Storybook's esbuild configuration
11
11
  // ------------------------------------------------------------
12
12
  import {
13
13
  createDocgenProvider
14
- } from "../_node-chunks/chunk-X7F7EONQ.js";
15
- import "../_node-chunks/chunk-GDY64HEP.js";
14
+ } from "../_node-chunks/chunk-P75AOQLO.js";
15
+ import "../_node-chunks/chunk-MMJPCIXK.js";
16
16
  export {
17
17
  createDocgenProvider
18
18
  };
@@ -11,18 +11,20 @@ interface CemTag {
11
11
  manifestPath: string;
12
12
  warning?: string;
13
13
  }
14
- interface CemSnapshot {
15
- /** First manifest in configuration order wins a tag. */
16
- tags: ReadonlyMap<string, CemTag>;
17
- /** Manifests that contribute nothing: missing or invalid with no last valid version. */
18
- errors: DocgenError[];
19
- paths: string[];
14
+ //#endregion
15
+ //#region code/renderers/web-components/.dts-emit/code/renderers/web-components/src/docgen/component-docgen/tag-resolver.d.ts
16
+ interface TagLookup {
17
+ storyFilePath: string;
18
+ }
19
+ interface TagResolver {
20
+ find(tag: string, lookup: TagLookup): Promise<CemTag | DocgenError>;
20
21
  }
21
22
  //#endregion
22
23
  //#region code/renderers/web-components/.dts-emit/code/renderers/web-components/src/docgen/component-docgen/build-docgen.d.ts
23
24
  interface WebComponentsDocgenOptions {
24
25
  manifestPaths: string[];
25
- typeProperty: string;
26
+ /** Also searched for element registrations when generating from sources. */
27
+ previewFilePath?: string;
26
28
  }
27
29
  type WebComponentsDocgenPayload = DocgenPayload & {
28
30
  /** Set while the manifest is served from its last valid version after a failed reload. */warning?: string;
@@ -32,18 +34,14 @@ type WebComponentsDocgenPayload = DocgenPayload & {
32
34
  };
33
35
  };
34
36
  interface BuildDocgenContext {
35
- cem: CemSnapshot;
36
- typeProperty: string;
37
+ resolver: TagResolver;
37
38
  }
38
- declare function buildDocgenPayload(input: DocgenProviderInput, context: BuildDocgenContext): WebComponentsDocgenPayload | undefined;
39
+ declare function buildDocgenPayload(input: DocgenProviderInput, context: BuildDocgenContext): Promise<WebComponentsDocgenPayload | undefined>;
39
40
  //#endregion
40
41
  //#region code/renderers/web-components/.dts-emit/code/renderers/web-components/src/docgen/docgen-worker.d.ts
41
42
  declare const createDocgenProvider: ({
42
43
  manifestPaths,
43
- typeProperty
44
+ previewFilePath
44
45
  }: WebComponentsDocgenOptions) => DocgenMiddleware;
45
46
  //#endregion
46
- //#region code/renderers/web-components/.dts-emit/code/renderers/web-components/src/docgen/component-docgen/arg-types/alt-type.d.ts
47
- declare const DEFAULT_TYPE_PROPERTY = "parsedType";
48
- //#endregion
49
- export { DEFAULT_TYPE_PROPERTY, type WebComponentsDocgenOptions, type WebComponentsDocgenPayload, buildDocgenPayload, createDocgenProvider };
47
+ export { type WebComponentsDocgenOptions, type WebComponentsDocgenPayload, buildDocgenPayload, createDocgenProvider };
@@ -1,10 +1,10 @@
1
- import CJS_COMPAT_NODE_URL_3ov4ld79bt3 from 'node:url';
2
- import CJS_COMPAT_NODE_PATH_3ov4ld79bt3 from 'node:path';
3
- import CJS_COMPAT_NODE_MODULE_3ov4ld79bt3 from "node:module";
1
+ import CJS_COMPAT_NODE_URL_seyt09815b from 'node:url';
2
+ import CJS_COMPAT_NODE_PATH_seyt09815b from 'node:path';
3
+ import CJS_COMPAT_NODE_MODULE_seyt09815b from "node:module";
4
4
 
5
- var __filename = CJS_COMPAT_NODE_URL_3ov4ld79bt3.fileURLToPath(import.meta.url);
6
- var __dirname = CJS_COMPAT_NODE_PATH_3ov4ld79bt3.dirname(__filename);
7
- var require = CJS_COMPAT_NODE_MODULE_3ov4ld79bt3.createRequire(import.meta.url);
5
+ var __filename = CJS_COMPAT_NODE_URL_seyt09815b.fileURLToPath(import.meta.url);
6
+ var __dirname = CJS_COMPAT_NODE_PATH_seyt09815b.dirname(__filename);
7
+ var require = CJS_COMPAT_NODE_MODULE_seyt09815b.createRequire(import.meta.url);
8
8
 
9
9
  // ------------------------------------------------------------
10
10
  // end of CJS compatibility banner, injected by Storybook's esbuild configuration
@@ -12,12 +12,9 @@ var require = CJS_COMPAT_NODE_MODULE_3ov4ld79bt3.createRequire(import.meta.url);
12
12
  import {
13
13
  buildDocgenPayload,
14
14
  createDocgenProvider
15
- } from "../_node-chunks/chunk-X7F7EONQ.js";
16
- import {
17
- DEFAULT_TYPE_PROPERTY
18
- } from "../_node-chunks/chunk-GDY64HEP.js";
15
+ } from "../_node-chunks/chunk-P75AOQLO.js";
16
+ import "../_node-chunks/chunk-MMJPCIXK.js";
19
17
  export {
20
- DEFAULT_TYPE_PROPERTY,
21
18
  buildDocgenPayload,
22
19
  createDocgenProvider
23
20
  };
@@ -2,8 +2,8 @@ import {
2
2
  getCustomElements,
3
3
  isValidComponent,
4
4
  isValidMetaData
5
- } from "./_browser-chunks/chunk-TXUT6K6E.js";
6
- import "./_browser-chunks/chunk-BNL7LBNI.js";
5
+ } from "./_browser-chunks/chunk-IPGO7UEM.js";
6
+ import "./_browser-chunks/chunk-CAPEJO4V.js";
7
7
  import "./_browser-chunks/chunk-EGBR6PF2.js";
8
8
  import "./_browser-chunks/chunk-4BE7D4DS.js";
9
9
 
@@ -11,7 +11,7 @@ import "./_browser-chunks/chunk-4BE7D4DS.js";
11
11
  import { enhanceArgTypes } from "storybook/internal/docs-tools";
12
12
 
13
13
  // src/docs/custom-elements.ts
14
- import { logger } from "storybook/internal/client-logger";
14
+ import { deprecate, logger } from "storybook/internal/client-logger";
15
15
 
16
16
  // ../../../node_modules/es-toolkit/dist/string/capitalize.mjs
17
17
  function capitalize(str) {
@@ -111,7 +111,9 @@ var getMetaDataExperimental = (tagName, customElements) => {
111
111
  declaration.tagName === tagName && (metadata = declaration);
112
112
  });
113
113
  }), metadata || logger.warn(`Component not found in custom-elements.json: ${tagName}`), metadata;
114
- }, getMetaData = (tagName, manifest) => manifest?.version === "experimental" ? getMetaDataExperimental(tagName, manifest) : getMetaDataV1(tagName, manifest), extractArgTypesFromElements = (tagName, customElements) => {
114
+ }, getMetaData = (tagName, manifest) => manifest?.version === "experimental" ? (deprecate(
115
+ "The web-component-analyzer Custom Elements Manifest shape is deprecated and will be removed in Storybook 12. Generate a Custom Elements Manifest with @custom-elements-manifest/analyzer instead."
116
+ ), getMetaDataExperimental(tagName, manifest)) : getMetaDataV1(tagName, manifest), extractArgTypesFromElements = (tagName, customElements) => {
115
117
  let metaData = getMetaData(tagName, customElements);
116
118
  return metaData && mapArgTypes(metaData);
117
119
  }, extractArgTypes = (tagName) => {
@@ -123,7 +125,7 @@ var getMetaDataExperimental = (tagName, customElements) => {
123
125
  };
124
126
 
125
127
  // src/entry-preview-argtypes.ts
126
- var parameters = {
128
+ var useServiceArgTypes = "FEATURES" in globalThis && globalThis.FEATURES?.docgenServer, parameters = useServiceArgTypes ? {} : {
127
129
  docs: {
128
130
  extractArgTypes,
129
131
  extractComponentDescription
@@ -2,7 +2,7 @@ import {
2
2
  parameters,
3
3
  render,
4
4
  renderToCanvas
5
- } from "./_browser-chunks/chunk-BNL7LBNI.js";
5
+ } from "./_browser-chunks/chunk-CAPEJO4V.js";
6
6
  import "./_browser-chunks/chunk-4BE7D4DS.js";
7
7
  export {
8
8
  parameters,
package/dist/index.d.ts CHANGED
@@ -8,14 +8,11 @@ type WebComponentsFrameworkOptions = {
8
8
  * Paths to Custom Elements Manifest files, relative to the Storybook config directory.
9
9
  *
10
10
  * When omitted, Storybook reads `customElements` from the nearest `package.json`.
11
- * When neither is available, server-side docgen is skipped and the runtime `setCustomElementsManifest` path keeps working as before.
11
+ * Tags no manifest declares are generated from the project's sources.
12
12
  *
13
- * Please note that the runtime `setCustomElementsManifest` path is deprecated and will be removed in next major.
13
+ * Please note that the runtime `setCustomElementsManifest` path is deprecated and will be removed in Storybook 12.
14
14
  */
15
15
  customElementsManifest?: string | string[];
16
- docgen?: {
17
- /** Manifest key that holds analyzer-resolved type text; defaults to `parsedType`. */typeProperty?: string;
18
- };
19
16
  };
20
17
  type StoryFnHtmlReturnType = string | Node | DocumentFragment | TemplateResult | SVGTemplateResult;
21
18
  interface WebComponentsRenderer extends WebRenderer {
@@ -49,11 +46,15 @@ type StoryContext<TArgs = StrictArgs$1> = StoryContext$1<WebComponentsRenderer,
49
46
  type Preview = ProjectAnnotations<WebComponentsRenderer>;
50
47
  //#endregion
51
48
  //#region code/renderers/web-components/.dts-emit/code/renderers/web-components/src/framework-api.d.ts
49
+ /** @deprecated Use framework.options.customElementsManifest with features.docgenServer instead. This runtime manifest helper will be removed in Storybook 12. */
52
50
  declare function isValidComponent(tagName: string): boolean;
51
+ /** @deprecated Use framework.options.customElementsManifest with features.docgenServer instead. This runtime manifest helper will be removed in Storybook 12. */
53
52
  declare function isValidMetaData(customElements: any): boolean;
54
- /** @param customElements `any` for now as spec is not super stable yet */
53
+ /** @deprecated Use framework.options.customElementsManifest with features.docgenServer instead. This runtime manifest setter will be removed in Storybook 12. */
55
54
  declare function setCustomElements(customElements: any): void;
55
+ /** @deprecated Use framework.options.customElementsManifest with features.docgenServer instead. This runtime manifest setter will be removed in Storybook 12. */
56
56
  declare function setCustomElementsManifest(customElements: any): void;
57
+ /** @deprecated Use framework.options.customElementsManifest with features.docgenServer instead. This runtime manifest getter will be removed in Storybook 12. */
57
58
  declare function getCustomElements(): any;
58
59
  //#endregion
59
60
  //#region code/renderers/web-components/.dts-emit/code/renderers/web-components/src/portable-stories.d.ts
package/dist/index.js CHANGED
@@ -6,8 +6,8 @@ import {
6
6
  setCustomElements,
7
7
  setCustomElementsManifest,
8
8
  setProjectAnnotations
9
- } from "./_browser-chunks/chunk-TXUT6K6E.js";
10
- import "./_browser-chunks/chunk-BNL7LBNI.js";
9
+ } from "./_browser-chunks/chunk-IPGO7UEM.js";
10
+ import "./_browser-chunks/chunk-CAPEJO4V.js";
11
11
  import "./_browser-chunks/chunk-EGBR6PF2.js";
12
12
  import "./_browser-chunks/chunk-4BE7D4DS.js";
13
13
  export {
package/dist/preset.js CHANGED
@@ -1,24 +1,24 @@
1
- import CJS_COMPAT_NODE_URL_3ov4ld79bt3 from 'node:url';
2
- import CJS_COMPAT_NODE_PATH_3ov4ld79bt3 from 'node:path';
3
- import CJS_COMPAT_NODE_MODULE_3ov4ld79bt3 from "node:module";
1
+ import CJS_COMPAT_NODE_URL_seyt09815b from 'node:url';
2
+ import CJS_COMPAT_NODE_PATH_seyt09815b from 'node:path';
3
+ import CJS_COMPAT_NODE_MODULE_seyt09815b from "node:module";
4
4
 
5
- var __filename = CJS_COMPAT_NODE_URL_3ov4ld79bt3.fileURLToPath(import.meta.url);
6
- var __dirname = CJS_COMPAT_NODE_PATH_3ov4ld79bt3.dirname(__filename);
7
- var require = CJS_COMPAT_NODE_MODULE_3ov4ld79bt3.createRequire(import.meta.url);
5
+ var __filename = CJS_COMPAT_NODE_URL_seyt09815b.fileURLToPath(import.meta.url);
6
+ var __dirname = CJS_COMPAT_NODE_PATH_seyt09815b.dirname(__filename);
7
+ var require = CJS_COMPAT_NODE_MODULE_seyt09815b.createRequire(import.meta.url);
8
8
 
9
9
  // ------------------------------------------------------------
10
10
  // end of CJS compatibility banner, injected by Storybook's esbuild configuration
11
11
  // ------------------------------------------------------------
12
12
  import {
13
- DEFAULT_TYPE_PROPERTY,
14
13
  parseStoryFile,
15
14
  resolveStoryComponent
16
- } from "./_node-chunks/chunk-GDY64HEP.js";
15
+ } from "./_node-chunks/chunk-MMJPCIXK.js";
17
16
 
18
17
  // src/preset.ts
19
18
  import { fileURLToPath as fileURLToPath3 } from "node:url";
20
19
 
21
20
  // src/docgen/preset.ts
21
+ import { loadPreviewOrConfigFile } from "storybook/internal/common";
22
22
  import { fileURLToPath } from "node:url";
23
23
 
24
24
  // src/docgen/component-docgen/config/resolve-manifest-paths.ts
@@ -46,7 +46,7 @@ var experimental_docgenProvider = async (existing = [], options) => {
46
46
  moduleSpecifier: fileURLToPath(import.meta.resolve(DOCGEN_WORKER_SPECIFIER)),
47
47
  options: {
48
48
  manifestPaths: resolveManifestPaths(options.configDir, frameworkOptions),
49
- typeProperty: frameworkOptions.docgen?.typeProperty ?? DEFAULT_TYPE_PROPERTY
49
+ previewFilePath: loadPreviewOrConfigFile({ configDir: options.configDir })
50
50
  }
51
51
  };
52
52
  return [...existing, descriptor];
@@ -1195,9 +1195,23 @@ function metaObjectPath(csf) {
1195
1195
 
1196
1196
  // ../../core/src/csf-tools/story-shape/normalize-story.ts
1197
1197
  function normalizeStoryDeclaration(storyDeclaration) {
1198
- let storyPath = declarationExpression(storyDeclaration), normalizedPath = bindInitializer(storyDeclaration, storyPath) ?? factoryArgumentExpression(storyPath), unwrappedPath = unwrapTypeExpression(normalizedPath);
1198
+ let storyPath = declarationExpression(storyDeclaration), resolvedStoryPath = resolveLocalStory(storyDeclaration, storyPath), normalizedPath = bindInitializer(storyDeclaration, resolvedStoryPath) ?? factoryArgumentExpression(resolvedStoryPath), unwrappedPath = unwrapTypeExpression(normalizedPath);
1199
1199
  return classifyStoryPath(unwrappedPath);
1200
1200
  }
1201
+ function resolveLocalStory(declaration, expression) {
1202
+ let visited = /* @__PURE__ */ new Set(), current2 = unwrapTypeExpression(expression);
1203
+ for (; current2.isIdentifier(); ) {
1204
+ let name = current2.node.name;
1205
+ if (visited.has(name) || !current2.scope.getBinding(name)?.constant)
1206
+ break;
1207
+ visited.add(name);
1208
+ let resolved = resolveIdentifierInit(declaration, current2);
1209
+ if (!resolved)
1210
+ break;
1211
+ current2 = unwrapTypeExpression(resolved);
1212
+ }
1213
+ return current2;
1214
+ }
1201
1215
  function declarationExpression(storyDeclaration) {
1202
1216
  if (storyDeclaration.isFunctionDeclaration())
1203
1217
  return storyDeclaration;
@@ -1378,10 +1392,15 @@ var membersOf = (object, ctx, visited) => {
1378
1392
  return importedBinding(ctx, binding.path, visited);
1379
1393
  if (!binding.constant)
1380
1394
  return;
1381
- let declared = declaredBindingMembers(ctx, binding.path.node, position, visited);
1395
+ let rootName = localAliasRoot(ctx, name), rootBinding = ctx.program.scope.getBinding(rootName), declared = declaredBindingMembers(
1396
+ ctx,
1397
+ rootBinding?.path.node ?? binding.path.node,
1398
+ position,
1399
+ visited
1400
+ );
1382
1401
  if (declared === void 0)
1383
1402
  return;
1384
- let assigned = assignedMembers(ctx, name, position);
1403
+ let assigned = assignedMembers(ctx, localAliases(ctx, rootName), position);
1385
1404
  return {
1386
1405
  kind: "members",
1387
1406
  ctx,
@@ -1405,6 +1424,14 @@ var membersOf = (object, ctx, visited) => {
1405
1424
  let factory = factoryCall(unwrapped);
1406
1425
  if (factory === void 0 && (t6.isFunction(unwrapped) || isCanonicalCsf2BindCall(unwrapped)))
1407
1426
  return { members: complete() };
1427
+ if (t6.isIdentifier(unwrapped)) {
1428
+ let referenced = bindingMembers(ctx, unwrapped.name, position, visited);
1429
+ if (referenced?.kind === "members") {
1430
+ let members = referenced.external ? ctx.externalize && externalized(referenced.members, referenced.ctx) : referenced.members;
1431
+ if (members)
1432
+ return { members, ...referenced.accessor ? { accessor: referenced.accessor } : {} };
1433
+ }
1434
+ }
1408
1435
  if (factory === void 0)
1409
1436
  return {
1410
1437
  members: { properties: {}, shadowed: [], unresolved: [sourceOf5(unwrapped)] }
@@ -1424,7 +1451,28 @@ var membersOf = (object, ctx, visited) => {
1424
1451
  },
1425
1452
  accessor: "input"
1426
1453
  };
1427
- }, MERGED_ANNOTATIONS = ["args", "argTypes", "parameters", "globals"], mergedAnnotations = (parent, child) => {
1454
+ }, MERGED_ANNOTATIONS = ["args", "argTypes", "parameters", "globals"], localAliasRoot = (ctx, name) => {
1455
+ let visited = /* @__PURE__ */ new Set(), current2 = name;
1456
+ for (; !visited.has(current2); ) {
1457
+ visited.add(current2);
1458
+ let binding = ctx.program.scope.getBinding(current2), node = binding?.path.node;
1459
+ if (!binding?.constant || !t6.isVariableDeclarator(node) || !node.init)
1460
+ break;
1461
+ let init = unwrapExpression4(node.init);
1462
+ if (!t6.isIdentifier(init))
1463
+ break;
1464
+ let target = ctx.program.scope.getBinding(init.name);
1465
+ if (!target?.constant || target.kind === "module")
1466
+ break;
1467
+ current2 = init.name;
1468
+ }
1469
+ return current2;
1470
+ }, localAliases = (ctx, root) => {
1471
+ let aliases = /* @__PURE__ */ new Map([[root, Number.NEGATIVE_INFINITY]]);
1472
+ for (let [name, binding] of Object.entries(ctx.program.scope.bindings))
1473
+ name !== root && binding.constant && localAliasRoot(ctx, name) === root && aliases.set(name, binding.path.node.start ?? Number.POSITIVE_INFINITY);
1474
+ return aliases;
1475
+ }, mergedAnnotations = (parent, child) => {
1428
1476
  let properties = { ...parent.properties, ...child.properties };
1429
1477
  for (let key of MERGED_ANNOTATIONS) {
1430
1478
  let from = parent.properties[key], over = child.properties[key];
@@ -1444,7 +1492,7 @@ var membersOf = (object, ctx, visited) => {
1444
1492
  parent: csfFactoryReceiver(node).name,
1445
1493
  ...config && t6.isObjectExpression(config) ? { config } : {}
1446
1494
  };
1447
- }, assignedMembers = (ctx, name, position) => {
1495
+ }, assignedMembers = (ctx, aliases, position) => {
1448
1496
  let properties = {}, unresolved = [];
1449
1497
  for (let statement of ctx.program.node.body) {
1450
1498
  if (!t6.isExpressionStatement(statement) || !t6.isAssignmentExpression(statement.expression))
@@ -1452,7 +1500,7 @@ var membersOf = (object, ctx, visited) => {
1452
1500
  let assignment = statement.expression, target = assignment.left, depth = 0, outermost;
1453
1501
  for (; t6.isMemberExpression(target); )
1454
1502
  depth += 1, outermost = t6.isIdentifier(target.property) && !target.computed ? target.property.name : t6.isStringLiteral(target.property) ? target.property.value : void 0, target = target.object;
1455
- if (!(depth === 0 || !t6.isIdentifier(target) || target.name !== name) && !(position !== void 0 && (assignment.start ?? 0) > position)) {
1503
+ if (!(depth === 0 || !t6.isIdentifier(target) || !aliases.has(target.name)) && !((assignment.start ?? 0) < aliases.get(target.name)) && !(position !== void 0 && (assignment.start ?? 0) > position)) {
1456
1504
  if (depth > 1 || outermost === void 0 || assignment.operator !== "=") {
1457
1505
  unresolved.push(sourceOf5(assignment));
1458
1506
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storybook/web-components",
3
- "version": "11.0.0-alpha.6",
3
+ "version": "11.0.0-alpha.7",
4
4
  "description": "Storybook Web Components renderer: Develop, document, and test UI components in isolation",
5
5
  "keywords": [
6
6
  "storybook",
@@ -54,9 +54,12 @@
54
54
  ],
55
55
  "dependencies": {
56
56
  "@storybook/global": "^5.0.0",
57
+ "@wc-toolkit/cem-generator": "^0.2.1",
58
+ "@wc-toolkit/cem-generator-lit": "^0.1.16",
57
59
  "custom-elements-manifest": "^2.1.0",
58
60
  "tiny-invariant": "^1.3.1",
59
- "ts-dedent": "^2.0.0"
61
+ "ts-dedent": "^2.2.0",
62
+ "typescript": "^6.0.3"
60
63
  },
61
64
  "devDependencies": {
62
65
  "@types/cross-spawn": "^6.0.6",
@@ -65,13 +68,13 @@
65
68
  "cross-spawn": "^7.0.6",
66
69
  "es-toolkit": "^1.43.0",
67
70
  "lit": "2.3.1",
71
+ "pathe": "^1.1.2",
68
72
  "tmp": "^0.2.3",
69
- "typescript": "^6.0.3",
70
73
  "web-component-analyzer": "^1.1.6"
71
74
  },
72
75
  "peerDependencies": {
73
76
  "lit": "^2.0.0 || ^3.0.0",
74
- "storybook": "^11.0.0-alpha.6"
77
+ "storybook": "^11.0.0-alpha.7"
75
78
  },
76
79
  "publishConfig": {
77
80
  "access": "public"
@@ -0,0 +1,176 @@
1
+ import { LitElement, css, html, nothing } from 'lit';
2
+
3
+ /**
4
+ * A counter that exposes every Custom Elements Manifest category the default render binds.
5
+ *
6
+ * @fires count-changed - Fires after the count changes, with the new count as `detail.count`
7
+ * @slot - Label shown next to the value
8
+ * @slot prefix - Content rendered before the label
9
+ * @cssprop {<color>} [--demo-wc-counter-accent=rgb(0, 95, 204)] - Background of the increment button
10
+ * @cssprop {<number>} [--demo-wc-counter-badge-opacity=1] - Opacity of the badges
11
+ * @csspart badge - A badge rendered next to the current count
12
+ * @csspart button - The increment button
13
+ * @csspart deadline - The deadline, when set
14
+ * @csspart value - The current count
15
+ * @cssstate at-max - Set while the count has reached `max`
16
+ */
17
+ export class DemoWcCounter extends LitElement {
18
+ static properties = {
19
+ count: { type: Number, reflect: true },
20
+ step: { type: Number },
21
+ max: { type: Number },
22
+ disabled: { type: Boolean, reflect: true },
23
+ size: { type: String, reflect: true },
24
+ tone: { type: String, reflect: true },
25
+ label: { type: String },
26
+ badges: { attribute: false },
27
+ unit: { attribute: false },
28
+ deadline: { attribute: false },
29
+ };
30
+
31
+ static styles = css`
32
+ :host {
33
+ display: inline-flex;
34
+ align-items: center;
35
+ gap: 8px;
36
+ font-family: sans-serif;
37
+ }
38
+
39
+ button {
40
+ border: none;
41
+ border-radius: 4px;
42
+ padding: 4px 12px;
43
+ color: white;
44
+ background: var(--demo-wc-counter-accent, rgb(0, 95, 204));
45
+ cursor: pointer;
46
+ }
47
+
48
+ :host([tone='success']) [part='value'] {
49
+ color: rgb(0, 128, 0);
50
+ }
51
+
52
+ :host([tone='danger']) [part='value'] {
53
+ color: rgb(220, 20, 60);
54
+ }
55
+
56
+ [part='badge'] {
57
+ opacity: var(--demo-wc-counter-badge-opacity, 1);
58
+ }
59
+
60
+ :host([size='small']) button {
61
+ font-size: 12px;
62
+ padding: 2px 8px;
63
+ }
64
+
65
+ :host([size='large']) button {
66
+ font-size: 20px;
67
+ padding: 8px 16px;
68
+ }
69
+
70
+ button:disabled {
71
+ opacity: 0.5;
72
+ cursor: not-allowed;
73
+ }
74
+ `;
75
+
76
+ #internals = this.attachInternals();
77
+
78
+ constructor() {
79
+ super();
80
+
81
+ /** Current value */
82
+ this.count = 0;
83
+
84
+ /** Amount added on every increment */
85
+ this.step = 1;
86
+
87
+ /** Highest value the counter can reach */
88
+ this.max = 10;
89
+
90
+ /** Prevents incrementing */
91
+ this.disabled = false;
92
+
93
+ /**
94
+ * Button size
95
+ *
96
+ * @type {'small' | 'medium' | 'large'}
97
+ */
98
+ this.size = 'medium';
99
+
100
+ /**
101
+ * Color of the value
102
+ *
103
+ * @type {'neutral' | 'info' | 'success' | 'warning' | 'danger' | 'brand'}
104
+ */
105
+ this.tone = 'neutral';
106
+
107
+ /** Accessible name of the increment button */
108
+ this.label = 'Increment';
109
+
110
+ /**
111
+ * Badges shown after the value, only settable as a property
112
+ *
113
+ * @type {Array<'new' | 'hot' | 'sale'>}
114
+ */
115
+ this.badges = [];
116
+
117
+ /**
118
+ * Words used after the value, only settable as a property
119
+ *
120
+ * @type {{ singular: string, plural: string }}
121
+ */
122
+ this.unit = { singular: 'click', plural: 'clicks' };
123
+
124
+ /**
125
+ * Date shown after the value, only settable as a property
126
+ *
127
+ * @type {Date | undefined}
128
+ */
129
+ this.deadline = undefined;
130
+ }
131
+
132
+ /** Whether the count has reached `max` */
133
+ get atMax() {
134
+ return this.count >= this.max;
135
+ }
136
+
137
+ /** Adds `step` to the count, up to `max` */
138
+ increment() {
139
+ if (this.disabled || this.atMax) {
140
+ return;
141
+ }
142
+ this.count = Math.min(this.count + this.step, this.max);
143
+ this.dispatchEvent(new CustomEvent('count-changed', { detail: { count: this.count } }));
144
+ }
145
+
146
+ updated() {
147
+ if (this.atMax) {
148
+ this.#internals.states.add('at-max');
149
+ } else {
150
+ this.#internals.states.delete('at-max');
151
+ }
152
+ }
153
+
154
+ render() {
155
+ const unit = this.count === 1 ? this.unit.singular : this.unit.plural;
156
+ return html`
157
+ <slot name="prefix"></slot>
158
+ <slot></slot>
159
+ <span part="value">${this.count} ${unit}</span>
160
+ ${this.badges.map((badge) => html`<span part="badge">${badge}</span>`)}
161
+ ${
162
+ this.deadline === undefined
163
+ ? nothing
164
+ : html`<time part="deadline">${new Date(this.deadline).toISOString().slice(0, 10)}</time>`
165
+ }
166
+ <button
167
+ part="button"
168
+ aria-label=${this.label}
169
+ ?disabled=${this.disabled || this.atMax}
170
+ @click=${this.increment}
171
+ >
172
+ +${this.step}
173
+ </button>
174
+ `;
175
+ }
176
+ }
@@ -0,0 +1,3 @@
1
+ import { DemoWcCounter } from './DemoWcCounter.js';
2
+
3
+ customElements.define('demo-wc-counter', DemoWcCounter);