@planningcenter/tapestry 1.8.1-rc.1 → 1.9.0-qa-312.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.
@@ -1,10 +1,13 @@
1
1
  import "../button/btn.css";
2
2
  import React, { AnchorHTMLAttributes } from "react";
3
3
  import { BaseComponentProps, ComponentKind } from "../../utilities/buttonLinkShared";
4
+ type ValidHref = `http://${string}` | `https://${string}` | `//${string}` | `/${string}` | `./${string}` | `../${string}` | string | `mailto:${string}` | `tel:${string}` | `sms:${string}` | `#${string}` | `?${string}` | `data:${string}` | `blob:${string}`;
4
5
  export interface BaseLinkElementProps extends BaseComponentProps, Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof BaseComponentProps | "children"> {
5
6
  children?: React.ReactNode;
7
+ href: ValidHref;
6
8
  kind?: ComponentKind;
7
9
  label?: React.ReactNode;
8
10
  }
9
11
  export declare const BaseLink: React.ForwardRefExoticComponent<BaseLinkElementProps & React.RefAttributes<HTMLAnchorElement>>;
12
+ export {};
10
13
  //# sourceMappingURL=BaseLink.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BaseLink.d.ts","sourceRoot":"","sources":["../../../src/components/link/BaseLink.tsx"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,CAAA;AAG1B,OAAO,KAAK,EAAE,EAAE,oBAAoB,EAAc,MAAM,OAAO,CAAA;AAE/D,OAAO,EACL,kBAAkB,EAGlB,aAAa,EAGd,MAAM,kCAAkC,CAAA;AAEzC,MAAM,WAAW,oBACf,SAAQ,kBAAkB,EACxB,IAAI,CACF,oBAAoB,CAAC,iBAAiB,CAAC,EACvC,MAAM,kBAAkB,GAAG,UAAU,CACtC;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACxB;AAeD,eAAO,MAAM,QAAQ,gGA4BpB,CAAA"}
1
+ {"version":3,"file":"BaseLink.d.ts","sourceRoot":"","sources":["../../../src/components/link/BaseLink.tsx"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,CAAA;AAG1B,OAAO,KAAK,EAAE,EAAE,oBAAoB,EAAc,MAAM,OAAO,CAAA;AAE/D,OAAO,EACL,kBAAkB,EAGlB,aAAa,EAGd,MAAM,kCAAkC,CAAA;AAGzC,KAAK,SAAS,GAEV,UAAU,MAAM,EAAE,GAClB,WAAW,MAAM,EAAE,GACnB,KAAK,MAAM,EAAE,GAEb,IAAI,MAAM,EAAE,GAEZ,KAAK,MAAM,EAAE,GACb,MAAM,MAAM,EAAE,GACd,MAAM,GAEN,UAAU,MAAM,EAAE,GAClB,OAAO,MAAM,EAAE,GACf,OAAO,MAAM,EAAE,GAEf,IAAI,MAAM,EAAE,GACZ,IAAI,MAAM,EAAE,GAEZ,QAAQ,MAAM,EAAE,GAChB,QAAQ,MAAM,EAAE,CAAA;AAEpB,MAAM,WAAW,oBACf,SAAQ,kBAAkB,EACxB,IAAI,CACF,oBAAoB,CAAC,iBAAiB,CAAC,EACvC,MAAM,kBAAkB,GAAG,UAAU,CACtC;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACxB;AAeD,eAAO,MAAM,QAAQ,gGAyDpB,CAAA"}
@@ -6,6 +6,29 @@ const buildComponentClassName = (size, kind, className) => {
6
6
  return classNames(kind && "tds-btn", size && size !== "md" && kind && COMPONENT_SIZE_CLASS_MAP[size], kind && COMPONENT_KIND_CLASS_MAP[kind], className);
7
7
  };
8
8
  const BaseLink = forwardRef(({ size, prefix, suffix, kind, label, children, className, href, ...restProps }, ref) => {
9
+ // Runtime validation for development (in case TypeScript is bypassed)
10
+ const forbiddenHrefs = ["#", "javascript:void(0)", ""];
11
+ if (process.env.NODE_ENV !== "production" &&
12
+ forbiddenHrefs.includes(href)) {
13
+ const errorMessage = `
14
+ ⚠️ Invalid href="${href}" detected in BaseLink component!
15
+
16
+ Reason: "${href}" is not suitable for production links.
17
+ • href="#" causes page jumps and poor accessibility
18
+ • href="javascript:void(0)" and empty hrefs are not allowed
19
+ • These patterns are problematic for navigation and accessibility
20
+
21
+ 💡 RECOMMENDED SOLUTION:
22
+ • Use a Button component instead if no navigation is needed
23
+ Example: <Button onClick={handleClick} label="Click me" />
24
+
25
+ Other solutions:
26
+ • Use real URLs like "https://example.com"
27
+ • Use relative paths like "/dashboard" or "/settings"
28
+ `.trim();
29
+ console.error(errorMessage);
30
+ throw new Error(`BaseLink: href="${href}" is not allowed. Use Button component if no navigation needed. See console for details.`);
31
+ }
9
32
  const combinedClassName = buildComponentClassName(size, kind, className);
10
33
  const prefixElement = enhanceElementWithClassName(prefix, "prefix");
11
34
  const suffixElement = enhanceElementWithClassName(suffix, "suffix");
@@ -1 +1 @@
1
- {"version":3,"file":"BaseLink.js","sources":["../../../src/components/link/BaseLink.tsx"],"sourcesContent":["import \"../button/btn.css\"\n\nimport classNames from \"classnames\"\nimport React, { AnchorHTMLAttributes, forwardRef } from \"react\"\n\nimport {\n BaseComponentProps,\n COMPONENT_KIND_CLASS_MAP,\n COMPONENT_SIZE_CLASS_MAP,\n ComponentKind,\n ComponentSize,\n enhanceElementWithClassName,\n} from \"../../utilities/buttonLinkShared\"\n\nexport interface BaseLinkElementProps\n extends BaseComponentProps,\n Omit<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n keyof BaseComponentProps | \"children\"\n > {\n children?: React.ReactNode\n kind?: ComponentKind\n label?: React.ReactNode\n}\n\nconst buildComponentClassName = (\n size?: ComponentSize,\n kind?: ComponentKind,\n className?: string\n): string => {\n return classNames(\n kind && \"tds-btn\",\n size && size !== \"md\" && kind && COMPONENT_SIZE_CLASS_MAP[size],\n kind && COMPONENT_KIND_CLASS_MAP[kind],\n className\n )\n}\n\nexport const BaseLink = forwardRef<HTMLAnchorElement, BaseLinkElementProps>(\n (\n {\n size,\n prefix,\n suffix,\n kind,\n label,\n children,\n className,\n href,\n ...restProps\n }: BaseLinkElementProps,\n ref\n ) => {\n const combinedClassName = buildComponentClassName(size, kind, className)\n\n const prefixElement = enhanceElementWithClassName(prefix, \"prefix\")\n const suffixElement = enhanceElementWithClassName(suffix, \"suffix\")\n\n return (\n <a href={href} className={combinedClassName} ref={ref} {...restProps}>\n {prefixElement}\n {label || children}\n {suffixElement}\n </a>\n )\n }\n)\n\nBaseLink.displayName = \"BaseLink\"\n"],"names":[],"mappings":";;;;AAyBA,MAAM,uBAAuB,GAAG,CAC9B,IAAoB,EACpB,IAAoB,EACpB,SAAkB,KACR;AACV,IAAA,OAAO,UAAU,CACf,IAAI,IAAI,SAAS,EACjB,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,wBAAwB,CAAC,IAAI,CAAC,EAC/D,IAAI,IAAI,wBAAwB,CAAC,IAAI,CAAC,EACtC,SAAS,CACV,CAAA;AACH,CAAC,CAAA;AAEM,MAAM,QAAQ,GAAG,UAAU,CAChC,CACE,EACE,IAAI,EACJ,MAAM,EACN,MAAM,EACN,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,SAAS,EACT,IAAI,EACJ,GAAG,SAAS,EACS,EACvB,GAAG,KACD;IACF,MAAM,iBAAiB,GAAG,uBAAuB,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,CAAA;IAExE,MAAM,aAAa,GAAG,2BAA2B,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IACnE,MAAM,aAAa,GAAG,2BAA2B,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;AAEnE,IAAA,QACE,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAG,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,iBAAiB,EAAE,GAAG,EAAE,GAAG,KAAM,SAAS,EAAA;QACjE,aAAa;AACb,QAAA,KAAK,IAAI,QAAQ;QACjB,aAAa,CACZ,EACL;AACH,CAAC,EACF;AAED,QAAQ,CAAC,WAAW,GAAG,UAAU;;;;"}
1
+ {"version":3,"file":"BaseLink.js","sources":["../../../src/components/link/BaseLink.tsx"],"sourcesContent":["import \"../button/btn.css\"\n\nimport classNames from \"classnames\"\nimport React, { AnchorHTMLAttributes, forwardRef } from \"react\"\n\nimport {\n BaseComponentProps,\n COMPONENT_KIND_CLASS_MAP,\n COMPONENT_SIZE_CLASS_MAP,\n ComponentKind,\n ComponentSize,\n enhanceElementWithClassName,\n} from \"../../utilities/buttonLinkShared\"\n\n// Only allow valid href patterns - excludes \"#\", \"javascript:*\", and empty strings\ntype ValidHref =\n // Full URLs\n | `http://${string}` // HTTP URLs: http://example.com\n | `https://${string}` // HTTPS URLs: https://example.com\n | `//${string}` // Protocol-relative: //example.com\n // Absolute paths\n | `/${string}` // Absolute paths: /dashboard, /api/users\n // Relative paths\n | `./${string}` // Relative to current: ./page.html, ./assets/file.pdf\n | `../${string}` // Relative to parent: ../index.html, ../images/logo.png\n | string // Simple relative: page.html, contact, docs\n // Communication protocols\n | `mailto:${string}` // Email links: mailto:user@example.com\n | `tel:${string}` // Phone links: tel:+1234567890\n | `sms:${string}` // SMS links: sms:+1234567890\n // Navigation anchors and queries\n | `#${string}` // Hash/fragment links: #section1, #top\n | `?${string}` // Query-only URLs: ?param=value&other=123\n // Data and file URLs\n | `data:${string}` // Inline data: data:image/png;base64,...\n | `blob:${string}` // Blob URLs: blob:https://example.com/uuid-here\n\nexport interface BaseLinkElementProps\n extends BaseComponentProps,\n Omit<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n keyof BaseComponentProps | \"children\"\n > {\n children?: React.ReactNode\n href: ValidHref\n kind?: ComponentKind\n label?: React.ReactNode\n}\n\nconst buildComponentClassName = (\n size?: ComponentSize,\n kind?: ComponentKind,\n className?: string\n): string => {\n return classNames(\n kind && \"tds-btn\",\n size && size !== \"md\" && kind && COMPONENT_SIZE_CLASS_MAP[size],\n kind && COMPONENT_KIND_CLASS_MAP[kind],\n className\n )\n}\n\nexport const BaseLink = forwardRef<HTMLAnchorElement, BaseLinkElementProps>(\n (\n {\n size,\n prefix,\n suffix,\n kind,\n label,\n children,\n className,\n href,\n ...restProps\n }: BaseLinkElementProps,\n ref\n ) => {\n // Runtime validation for development (in case TypeScript is bypassed)\n const forbiddenHrefs = [\"#\", \"javascript:void(0)\", \"\"]\n if (\n process.env.NODE_ENV !== \"production\" &&\n forbiddenHrefs.includes(href as string)\n ) {\n const errorMessage = `\n⚠️ Invalid href=\"${href}\" detected in BaseLink component!\n\nReason: \"${href}\" is not suitable for production links.\n• href=\"#\" causes page jumps and poor accessibility\n• href=\"javascript:void(0)\" and empty hrefs are not allowed\n• These patterns are problematic for navigation and accessibility\n\n💡 RECOMMENDED SOLUTION:\n• Use a Button component instead if no navigation is needed\n Example: <Button onClick={handleClick} label=\"Click me\" />\n\nOther solutions:\n• Use real URLs like \"https://example.com\"\n• Use relative paths like \"/dashboard\" or \"/settings\"\n `.trim()\n\n console.error(errorMessage)\n throw new Error(\n `BaseLink: href=\"${href}\" is not allowed. Use Button component if no navigation needed. See console for details.`\n )\n }\n\n const combinedClassName = buildComponentClassName(size, kind, className)\n\n const prefixElement = enhanceElementWithClassName(prefix, \"prefix\")\n const suffixElement = enhanceElementWithClassName(suffix, \"suffix\")\n\n return (\n <a href={href} className={combinedClassName} ref={ref} {...restProps}>\n {prefixElement}\n {label || children}\n {suffixElement}\n </a>\n )\n }\n)\n\nBaseLink.displayName = \"BaseLink\"\n"],"names":[],"mappings":";;;;AAiDA,MAAM,uBAAuB,GAAG,CAC9B,IAAoB,EACpB,IAAoB,EACpB,SAAkB,KACR;AACV,IAAA,OAAO,UAAU,CACf,IAAI,IAAI,SAAS,EACjB,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,wBAAwB,CAAC,IAAI,CAAC,EAC/D,IAAI,IAAI,wBAAwB,CAAC,IAAI,CAAC,EACtC,SAAS,CACV,CAAA;AACH,CAAC,CAAA;AAEM,MAAM,QAAQ,GAAG,UAAU,CAChC,CACE,EACE,IAAI,EACJ,MAAM,EACN,MAAM,EACN,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,SAAS,EACT,IAAI,EACJ,GAAG,SAAS,EACS,EACvB,GAAG,KACD;;IAEF,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,oBAAoB,EAAE,EAAE,CAAC,CAAA;AACtD,IAAA,IACE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;AACrC,QAAA,cAAc,CAAC,QAAQ,CAAC,IAAc,CAAC,EACvC;AACA,QAAA,MAAM,YAAY,GAAG,CAAA;oBACP,IAAI,CAAA;;WAEb,IAAI,CAAA;;;;;;;;;;;;OAYR,CAAC,IAAI,EAAE,CAAA;AAER,QAAA,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;AAC3B,QAAA,MAAM,IAAI,KAAK,CACb,mBAAmB,IAAI,CAAA,wFAAA,CAA0F,CAClH,CAAA;KACF;IAED,MAAM,iBAAiB,GAAG,uBAAuB,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,CAAA;IAExE,MAAM,aAAa,GAAG,2BAA2B,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IACnE,MAAM,aAAa,GAAG,2BAA2B,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;AAEnE,IAAA,QACE,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAG,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,iBAAiB,EAAE,GAAG,EAAE,GAAG,KAAM,SAAS,EAAA;QACjE,aAAa;AACb,QAAA,KAAK,IAAI,QAAQ;QACjB,aAAa,CACZ,EACL;AACH,CAAC,EACF;AAED,QAAQ,CAAC,WAAW,GAAG,UAAU;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/tapestry",
3
- "version": "1.8.1-rc.1",
3
+ "version": "1.9.0-qa-312.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "types": "./dist/index.d.ts",
42
42
  "devDependencies": {
43
- "@planningcenter/tapestry-render": "^1.7.0",
43
+ "@planningcenter/tapestry-render": "^1.9.0-qa-312.0",
44
44
  "@rollup/plugin-commonjs": "^26.0.1",
45
45
  "@rollup/plugin-node-resolve": "^15.2.3",
46
46
  "@rollup/plugin-typescript": "^11.1.6",
@@ -85,7 +85,7 @@
85
85
  "shadow-dom-testing-library": "^1.11.3",
86
86
  "storybook": "^9.0.17",
87
87
  "style-dictionary": "^4.2.0",
88
- "tapestry-wc": "^1.7.0",
88
+ "tapestry-wc": "^1.9.0-qa-312.0",
89
89
  "typescript": "^5.5.3",
90
90
  "vite": "6.3.4",
91
91
  "vitest": "^3.0.0"
@@ -95,5 +95,5 @@
95
95
  "classnames": "^2.5.1",
96
96
  "lodash": "^4.17.21"
97
97
  },
98
- "gitHead": "39cc813ff2dd72ca00d700124436c4e02412b202"
98
+ "gitHead": "3d3cbdc55c4b89cd197e07bcda3cc5476d32ef81"
99
99
  }