@sproutsocial/seeds-react-link 1.1.6 → 1.1.12

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.
@@ -8,14 +8,14 @@ $ tsup --dts
8
8
  CLI Cleaning output folder
9
9
  CJS Build start
10
10
  ESM Build start
11
- CJS dist/index.js 4.36 KB
12
- CJS dist/index.js.map 5.70 KB
11
+ CJS dist/index.js 6.97 KB
12
+ CJS dist/index.js.map 11.31 KB
13
13
  CJS ⚡️ Build success in 82ms
14
- ESM dist/esm/index.js 2.43 KB
15
- ESM dist/esm/index.js.map 5.67 KB
16
- ESM ⚡️ Build success in 82ms
14
+ ESM dist/esm/index.js 4.89 KB
15
+ ESM dist/esm/index.js.map 11.24 KB
16
+ ESM ⚡️ Build success in 83ms
17
17
  DTS Build start
18
- DTS ⚡️ Build success in 4618ms
19
- DTS dist/index.d.ts 1.19 KB
20
- DTS dist/index.d.mts 1.19 KB
21
- Done in 6.36s.
18
+ DTS ⚡️ Build success in 6217ms
19
+ DTS dist/index.d.ts 1.40 KB
20
+ DTS dist/index.d.mts 1.40 KB
21
+ Done in 7.82s.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,56 @@
1
1
  # @sproutsocial/seeds-react-link
2
2
 
3
+ ## 1.1.12
4
+
5
+ ### Patch Changes
6
+
7
+ - edc1819: Migrate link, text, banner, loader-button, and content-header to the Tailwind hybrid pattern (mirroring seeds-react-button). Each component gains a pure CSS-class `*Tailwind` implementation, a `*Hybrid` router that falls back to styled-components when system/styled props are present, and a component-scoped CSS file of `seeds-*` classes built on `var(--…)` tokens. Component CSS is wrapped in `@layer components` so consumer Tailwind utility overrides win the cascade, and the per-component CSS import is dropped from the `*Tailwind` files since the CSS is aggregated into `@sproutsocial/racine/css/components` at build time. Legacy `styles.ts` paths are unchanged.
8
+ - Updated dependencies [edc1819]
9
+ - @sproutsocial/seeds-react-text@1.4.3
10
+
11
+ ## 1.1.11
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies [5892f44]
16
+ - @sproutsocial/seeds-react-system-props@3.1.1
17
+ - @sproutsocial/seeds-react-text@1.4.2
18
+
19
+ ## 1.1.10
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies [5114a32]
24
+ - @sproutsocial/seeds-react-theme@4.1.0
25
+ - @sproutsocial/seeds-react-mixins@4.3.7
26
+
27
+ ## 1.1.9
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies [132ef9d]
32
+ - Updated dependencies [132ef9d]
33
+ - @sproutsocial/seeds-react-theme@4.0.0
34
+ - @sproutsocial/seeds-react-system-props@3.1.0
35
+ - @sproutsocial/seeds-react-mixins@4.3.6
36
+ - @sproutsocial/seeds-react-text@1.4.1
37
+
38
+ ## 1.1.8
39
+
40
+ ### Patch Changes
41
+
42
+ - Updated dependencies [47c62b3]
43
+ - @sproutsocial/seeds-react-theme@3.7.1
44
+ - @sproutsocial/seeds-react-mixins@4.3.5
45
+
46
+ ## 1.1.7
47
+
48
+ ### Patch Changes
49
+
50
+ - Updated dependencies [06da9c2]
51
+ - @sproutsocial/seeds-react-theme@3.7.0
52
+ - @sproutsocial/seeds-react-mixins@4.3.4
53
+
3
54
  ## 1.1.6
4
55
 
5
56
  ### Patch Changes
package/dist/esm/index.js CHANGED
@@ -1,5 +1,8 @@
1
1
  // src/Link.tsx
2
- import * as React from "react";
2
+ import * as React3 from "react";
3
+
4
+ // src/LinkHybrid.tsx
5
+ import * as React2 from "react";
3
6
 
4
7
  // src/styles.ts
5
8
  import styled, { css } from "styled-components";
@@ -52,9 +55,26 @@ var Container = styled(Text)`
52
55
  `;
53
56
  var styles_default = Container;
54
57
 
55
- // src/Link.tsx
58
+ // src/LinkTailwind.tsx
59
+ import * as React from "react";
56
60
  import { jsx } from "react/jsx-runtime";
57
- var Link = React.forwardRef(
61
+ function cn(...inputs) {
62
+ const classes = [];
63
+ for (const input of inputs) {
64
+ if (!input) continue;
65
+ if (typeof input === "string") {
66
+ classes.push(input);
67
+ } else if (typeof input === "object") {
68
+ for (const [key, value] of Object.entries(input)) {
69
+ if (value) {
70
+ classes.push(key);
71
+ }
72
+ }
73
+ }
74
+ }
75
+ return classes.join(" ");
76
+ }
77
+ var LinkTailwind = React.forwardRef(
58
78
  ({
59
79
  href,
60
80
  external,
@@ -64,27 +84,32 @@ var Link = React.forwardRef(
64
84
  as,
65
85
  underline = true,
66
86
  qa = {},
87
+ className,
67
88
  ...rest
68
89
  }, ref) => {
69
- if (!href && external) {
70
- console.warn(
71
- "Warning: external prop cannot be set without a href declaration"
72
- );
73
- }
74
90
  const type = as || (href ? "a" : "button");
91
+ const Component = type;
92
+ const classes = cn(
93
+ "seeds-link",
94
+ {
95
+ "seeds-link-underline": !!underline,
96
+ "seeds-link-disabled": !!disabled2,
97
+ "seeds-link-no-href": !href
98
+ },
99
+ className
100
+ );
75
101
  return /* @__PURE__ */ jsx(
76
- styles_default,
102
+ Component,
77
103
  {
78
104
  ref,
79
105
  href,
80
106
  target: external ? "_blank" : void 0,
81
107
  type: type === "button" ? "button" : void 0,
82
108
  rel: external ? "noopener noreferrer" : void 0,
83
- forwardedAs: type,
84
109
  "aria-disabled": disabled2 ? disabled2 : void 0,
85
110
  disabled: disabled2,
86
111
  onClick,
87
- underline,
112
+ className: classes,
88
113
  "data-qa-link": "",
89
114
  "data-qa-link-isdisabled": disabled2 === true,
90
115
  ...qa,
@@ -94,6 +119,85 @@ var Link = React.forwardRef(
94
119
  );
95
120
  }
96
121
  );
122
+ LinkTailwind.displayName = "LinkTailwind";
123
+
124
+ // src/LinkHybrid.tsx
125
+ import { hasStyledProps } from "@sproutsocial/seeds-react-system-props";
126
+ import { jsx as jsx2 } from "react/jsx-runtime";
127
+ var TYPOGRAPHY_KEYS = [
128
+ "fontSize",
129
+ "typeScale",
130
+ "fontWeight",
131
+ "textAlign",
132
+ "lineHeight",
133
+ "isItalicized",
134
+ "fontFamily",
135
+ "fontStyle"
136
+ ];
137
+ var hasLinkStyledProps = (props) => hasStyledProps(props) || TYPOGRAPHY_KEYS.some((key) => props[key] !== void 0);
138
+ var LinkHybrid = React2.forwardRef(
139
+ ({
140
+ href,
141
+ external,
142
+ children,
143
+ disabled: disabled2,
144
+ onClick,
145
+ as,
146
+ underline = true,
147
+ qa = {},
148
+ ...rest
149
+ }, ref) => {
150
+ if (!href && external) {
151
+ console.warn(
152
+ "Warning: external prop cannot be set without a href declaration"
153
+ );
154
+ }
155
+ const type = as || (href ? "a" : "button");
156
+ if (hasLinkStyledProps(rest)) {
157
+ return /* @__PURE__ */ jsx2(
158
+ styles_default,
159
+ {
160
+ ref,
161
+ href,
162
+ target: external ? "_blank" : void 0,
163
+ type: type === "button" ? "button" : void 0,
164
+ rel: external ? "noopener noreferrer" : void 0,
165
+ forwardedAs: type,
166
+ "aria-disabled": disabled2 ? disabled2 : void 0,
167
+ disabled: disabled2,
168
+ onClick,
169
+ underline,
170
+ "data-qa-link": "",
171
+ "data-qa-link-isdisabled": disabled2 === true,
172
+ ...qa,
173
+ ...rest,
174
+ children
175
+ }
176
+ );
177
+ }
178
+ return /* @__PURE__ */ jsx2(
179
+ LinkTailwind,
180
+ {
181
+ ref,
182
+ href,
183
+ external,
184
+ disabled: disabled2,
185
+ onClick,
186
+ as,
187
+ underline,
188
+ qa,
189
+ ...rest,
190
+ children
191
+ }
192
+ );
193
+ }
194
+ );
195
+ LinkHybrid.displayName = "Link";
196
+ var LinkHybrid_default = LinkHybrid;
197
+
198
+ // src/Link.tsx
199
+ import { jsx as jsx3 } from "react/jsx-runtime";
200
+ var Link = React3.forwardRef((props, ref) => /* @__PURE__ */ jsx3(LinkHybrid_default, { ...props, ref }));
97
201
  Link.displayName = "Link";
98
202
  var Link_default = Link;
99
203
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/Link.tsx","../../src/styles.ts","../../src/LinkTypes.ts","../../src/constants.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport Container from \"./styles\";\nimport type { TypeLinkProps } from \"./LinkTypes\";\n\nconst Link = React.forwardRef<\n HTMLAnchorElement | HTMLButtonElement,\n TypeLinkProps\n>(\n (\n {\n href,\n external,\n children,\n disabled,\n onClick,\n as,\n underline = true,\n qa = {},\n ...rest\n },\n ref\n ) => {\n if (!href && external) {\n // eslint-disable-next-line no-console\n console.warn(\n \"Warning: external prop cannot be set without a href declaration\"\n );\n }\n\n const type = as || (href ? \"a\" : \"button\");\n return (\n <Container\n ref={ref}\n href={href}\n target={external ? \"_blank\" : undefined}\n type={type === \"button\" ? \"button\" : undefined}\n rel={external ? \"noopener noreferrer\" : undefined}\n forwardedAs={type}\n aria-disabled={disabled ? disabled : undefined}\n disabled={disabled}\n onClick={onClick}\n underline={underline}\n data-qa-link=\"\"\n data-qa-link-isdisabled={disabled === true}\n {...qa}\n {...rest}\n >\n {children}\n </Container>\n );\n }\n);\n\nLink.displayName = \"Link\";\n\nexport default Link;\n","import styled, { css } from \"styled-components\";\nimport {\n TYPOGRAPHY,\n COMMON,\n FLEXBOX,\n} from \"@sproutsocial/seeds-react-system-props\";\nimport { focusRing, disabled } from \"@sproutsocial/seeds-react-mixins\";\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport type { TypeLinkProps } from \"./LinkTypes\";\n\nconst Container = styled(Text)<TypeLinkProps>`\n border: 0;\n font-family: ${(props) => props.theme.fontFamily};\n text-decoration: ${(props) => (props.underline ? \"underline\" : \"none\")};\n appearance: none;\n cursor: pointer;\n ${(props) =>\n props.disabled &&\n css`\n opacity: 0.4;\n cursor: not-allowed;\n `}\n font-weight: ${(props) => props.theme.fontWeights.semibold};\n color: ${(props) => props.theme.colors.link.base};\n\n &:hover {\n color: ${(props) => props.theme.colors.link.hover};\n text-decoration: underline;\n }\n\n &:active {\n color: ${(props) => props.theme.colors.link.hover};\n }\n\n &:focus {\n ${focusRing}\n }\n\n &:focus:active {\n box-shadow: none;\n }\n\n ${(props) =>\n !props.href &&\n css`\n background: none;\n `}\n\n ${(props) => props.disabled && disabled}\n\n ${COMMON}\n ${TYPOGRAPHY}\n ${FLEXBOX}\n`;\n\nexport default Container;\n","import * as React from \"react\";\nimport type { TypeStyledComponentsCommonProps } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeTextProps } from \"@sproutsocial/seeds-react-text\";\nimport type { TypeSystemFlexboxProps } from \"@sproutsocial/seeds-react-system-props\";\n\nexport interface TypeLinkProps\n extends Omit<\n TypeTextProps,\n keyof Omit<React.ComponentPropsWithoutRef<\"span\">, \"color\">\n >,\n Omit<React.ComponentPropsWithoutRef<\"button\">, \"color\">,\n TypeSystemFlexboxProps {\n /** Optional prop to make the URL open in a new tab */\n external?: boolean;\n children: React.ReactNode;\n\n /** Setting this prop will cause the component to be rendered as a link */\n href?: string;\n\n /** Disables user action and applies a disabled style to the component */\n disabled?: boolean;\n\n /** Can be used in addition to an href but still renders as a link. Omitting href will render as button */\n onClick?: (e: React.SyntheticEvent<HTMLButtonElement>) => void;\n as?: TypeStyledComponentsCommonProps[\"as\"];\n underline?: boolean;\n qa?: { [key: string]: unknown }; // should this be string|number?\n}\n","import { COLOR_BLUE_900 } from \"@sproutsocial/seeds-color\";\n\nconst defaultLink = {\n color: \"link\",\n hoverColor: \"link.hover\",\n activeColor: COLOR_BLUE_900,\n fontWeight: \"semibold\",\n};\n\nconst linkTheme = {\n default: defaultLink,\n};\n\nexport default linkTheme;\n","import Link from \"./Link\";\n\nexport default Link;\nexport { Link };\nexport * from \"./LinkTypes\";\nexport * from \"./constants\";\n"],"mappings":";AAAA,YAAY,WAAW;;;ACAvB,OAAO,UAAU,WAAW;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,WAAW,gBAAgB;AACpC,OAAO,UAAU;AAGjB,IAAM,YAAY,OAAO,IAAI;AAAA;AAAA,iBAEZ,CAAC,UAAU,MAAM,MAAM,UAAU;AAAA,qBAC7B,CAAC,UAAW,MAAM,YAAY,cAAc,MAAO;AAAA;AAAA;AAAA,IAGpE,CAAC,UACD,MAAM,YACN;AAAA;AAAA;AAAA,KAGC;AAAA,iBACY,CAAC,UAAU,MAAM,MAAM,YAAY,QAAQ;AAAA,WACjD,CAAC,UAAU,MAAM,MAAM,OAAO,KAAK,IAAI;AAAA;AAAA;AAAA,aAGrC,CAAC,UAAU,MAAM,MAAM,OAAO,KAAK,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,aAKxC,CAAC,UAAU,MAAM,MAAM,OAAO,KAAK,KAAK;AAAA;AAAA;AAAA;AAAA,MAI/C,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOX,CAAC,UACD,CAAC,MAAM,QACP;AAAA;AAAA,KAEC;AAAA;AAAA,IAED,CAAC,UAAU,MAAM,YAAY,QAAQ;AAAA;AAAA,KAEpC,MAAM;AAAA,KACN,UAAU;AAAA,KACV,OAAO;AAAA;AAGZ,IAAO,iBAAQ;;;ADxBT;AA3BN,IAAM,OAAa;AAAA,EAIjB,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAAA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,KAAK,CAAC;AAAA,IACN,GAAG;AAAA,EACL,GACA,QACG;AACH,QAAI,CAAC,QAAQ,UAAU;AAErB,cAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAEA,UAAM,OAAO,OAAO,OAAO,MAAM;AACjC,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,QAAQ,WAAW,WAAW;AAAA,QAC9B,MAAM,SAAS,WAAW,WAAW;AAAA,QACrC,KAAK,WAAW,wBAAwB;AAAA,QACxC,aAAa;AAAA,QACb,iBAAeA,YAAWA,YAAW;AAAA,QACrC,UAAUA;AAAA,QACV;AAAA,QACA;AAAA,QACA,gBAAa;AAAA,QACb,2BAAyBA,cAAa;AAAA,QACrC,GAAG;AAAA,QACH,GAAG;AAAA,QAEH;AAAA;AAAA,IACH;AAAA,EAEJ;AACF;AAEA,KAAK,cAAc;AAEnB,IAAO,eAAQ;;;AEvDf,OAAuB;;;ACAvB,SAAS,sBAAsB;;;ACE/B,IAAO,gBAAQ;","names":["disabled"]}
1
+ {"version":3,"sources":["../../src/Link.tsx","../../src/LinkHybrid.tsx","../../src/styles.ts","../../src/LinkTailwind.tsx","../../src/LinkTypes.ts","../../src/constants.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport LinkHybrid from \"./LinkHybrid\";\nimport type { TypeLinkProps } from \"./LinkTypes\";\n\n/**\n * Link component. Automatically routes between the Tailwind implementation\n * (preferred) and the styled-components implementation (for consumers using\n * system/typography props or a styled() extension).\n */\nconst Link = React.forwardRef<\n HTMLAnchorElement | HTMLButtonElement,\n TypeLinkProps\n>((props, ref) => <LinkHybrid {...props} ref={ref} />);\n\nLink.displayName = \"Link\";\n\nexport default Link;\n","/**\n * Hybrid Link Component\n * Automatically chooses between Tailwind and styled-components based on props.\n *\n * Link's underlying Container is `styled(Text)`, so it accepts typography props\n * (e.g. `fontSize`). `hasStyledProps` does not include typography props, so we\n * additionally route to the styled-components path when any typography prop is\n * present — mirroring Text — so font sizing is never silently dropped.\n */\n\nimport * as React from \"react\";\nimport Container from \"./styles\"; // Styled-components version\nimport { LinkTailwind } from \"./LinkTailwind\"; // Tailwind version\nimport { hasStyledProps } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeLinkProps } from \"./LinkTypes\";\n\nconst TYPOGRAPHY_KEYS = [\n \"fontSize\",\n \"typeScale\",\n \"fontWeight\",\n \"textAlign\",\n \"lineHeight\",\n \"isItalicized\",\n \"fontFamily\",\n \"fontStyle\",\n] as const;\n\nconst hasLinkStyledProps = (props: Record<string, unknown>): boolean =>\n hasStyledProps(props) ||\n TYPOGRAPHY_KEYS.some((key) => props[key] !== undefined);\n\nconst LinkHybrid = React.forwardRef<\n HTMLAnchorElement | HTMLButtonElement,\n TypeLinkProps\n>(\n (\n {\n href,\n external,\n children,\n disabled,\n onClick,\n as,\n underline = true,\n qa = {},\n ...rest\n },\n ref\n ) => {\n if (!href && external) {\n // eslint-disable-next-line no-console\n console.warn(\n \"Warning: external prop cannot be set without a href declaration\"\n );\n }\n\n const type = as || (href ? \"a\" : \"button\");\n\n if (hasLinkStyledProps(rest)) {\n return (\n <Container\n ref={ref}\n href={href}\n target={external ? \"_blank\" : undefined}\n type={type === \"button\" ? \"button\" : undefined}\n rel={external ? \"noopener noreferrer\" : undefined}\n forwardedAs={type}\n aria-disabled={disabled ? disabled : undefined}\n disabled={disabled}\n onClick={onClick}\n underline={underline}\n data-qa-link=\"\"\n data-qa-link-isdisabled={disabled === true}\n {...qa}\n {...rest}\n >\n {children}\n </Container>\n );\n }\n\n // Use Tailwind version (preferred - better performance)\n return (\n <LinkTailwind\n ref={ref}\n href={href}\n external={external}\n disabled={disabled}\n onClick={onClick}\n as={as}\n underline={underline}\n qa={qa}\n {...rest}\n >\n {children}\n </LinkTailwind>\n );\n }\n);\n\nLinkHybrid.displayName = \"Link\";\n\nexport default LinkHybrid;\n","import styled, { css } from \"styled-components\";\nimport {\n TYPOGRAPHY,\n COMMON,\n FLEXBOX,\n} from \"@sproutsocial/seeds-react-system-props\";\nimport { focusRing, disabled } from \"@sproutsocial/seeds-react-mixins\";\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport type { TypeLinkProps } from \"./LinkTypes\";\n\nconst Container = styled(Text)<TypeLinkProps>`\n border: 0;\n font-family: ${(props) => props.theme.fontFamily};\n text-decoration: ${(props) => (props.underline ? \"underline\" : \"none\")};\n appearance: none;\n cursor: pointer;\n ${(props) =>\n props.disabled &&\n css`\n opacity: 0.4;\n cursor: not-allowed;\n `}\n font-weight: ${(props) => props.theme.fontWeights.semibold};\n color: ${(props) => props.theme.colors.link.base};\n\n &:hover {\n color: ${(props) => props.theme.colors.link.hover};\n text-decoration: underline;\n }\n\n &:active {\n color: ${(props) => props.theme.colors.link.hover};\n }\n\n &:focus {\n ${focusRing}\n }\n\n &:focus:active {\n box-shadow: none;\n }\n\n ${(props) =>\n !props.href &&\n css`\n background: none;\n `}\n\n ${(props) => props.disabled && disabled}\n\n ${COMMON}\n ${TYPOGRAPHY}\n ${FLEXBOX}\n`;\n\nexport default Container;\n","/**\n * Tailwind CSS implementation of Link component\n * Uses Seeds link CSS classes from link.css\n */\n\nimport * as React from \"react\";\nimport type { TypeLinkProps } from \"./LinkTypes\";\n\n// Utility for merging class names properly\nfunction cn(\n ...inputs: (string | undefined | null | false | Record<string, boolean>)[]\n): string {\n const classes: string[] = [];\n\n for (const input of inputs) {\n if (!input) continue;\n\n if (typeof input === \"string\") {\n classes.push(input);\n } else if (typeof input === \"object\") {\n for (const [key, value] of Object.entries(input)) {\n if (value) {\n classes.push(key);\n }\n }\n }\n }\n\n return classes.join(\" \");\n}\n\nexport const LinkTailwind = React.forwardRef<\n HTMLAnchorElement | HTMLButtonElement,\n TypeLinkProps\n>(\n (\n {\n href,\n external,\n children,\n disabled,\n onClick,\n as,\n underline = true,\n qa = {},\n className,\n ...rest\n },\n ref\n ) => {\n const type = as || (href ? \"a\" : \"button\");\n const Component = type as any;\n\n const classes = cn(\n \"seeds-link\",\n {\n \"seeds-link-underline\": !!underline,\n \"seeds-link-disabled\": !!disabled,\n \"seeds-link-no-href\": !href,\n },\n className\n );\n\n return (\n <Component\n ref={ref}\n href={href}\n target={external ? \"_blank\" : undefined}\n type={type === \"button\" ? \"button\" : undefined}\n rel={external ? \"noopener noreferrer\" : undefined}\n aria-disabled={disabled ? disabled : undefined}\n disabled={disabled}\n onClick={onClick}\n className={classes}\n data-qa-link=\"\"\n data-qa-link-isdisabled={disabled === true}\n {...qa}\n {...rest}\n >\n {children}\n </Component>\n );\n }\n);\n\nLinkTailwind.displayName = \"LinkTailwind\";\n","import * as React from \"react\";\nimport type { TypeStyledComponentsCommonProps } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeTextProps } from \"@sproutsocial/seeds-react-text\";\nimport type { TypeSystemFlexboxProps } from \"@sproutsocial/seeds-react-system-props\";\n\nexport interface TypeLinkProps\n extends Omit<\n TypeTextProps,\n keyof Omit<React.ComponentPropsWithoutRef<\"span\">, \"color\">\n >,\n Omit<React.ComponentPropsWithoutRef<\"button\">, \"color\">,\n TypeSystemFlexboxProps {\n /** Optional prop to make the URL open in a new tab */\n external?: boolean;\n children: React.ReactNode;\n\n /** Setting this prop will cause the component to be rendered as a link */\n href?: string;\n\n /** Disables user action and applies a disabled style to the component */\n disabled?: boolean;\n\n /** Can be used in addition to an href but still renders as a link. Omitting href will render as button */\n onClick?: (e: React.SyntheticEvent<HTMLButtonElement>) => void;\n as?: TypeStyledComponentsCommonProps[\"as\"];\n underline?: boolean;\n qa?: { [key: string]: unknown }; // should this be string|number?\n}\n","import { COLOR_BLUE_900 } from \"@sproutsocial/seeds-color\";\n\nconst defaultLink = {\n color: \"link\",\n hoverColor: \"link.hover\",\n activeColor: COLOR_BLUE_900,\n fontWeight: \"semibold\",\n};\n\nconst linkTheme = {\n default: defaultLink,\n};\n\nexport default linkTheme;\n","import Link from \"./Link\";\n\nexport default Link;\nexport { Link };\nexport * from \"./LinkTypes\";\nexport * from \"./constants\";\n"],"mappings":"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","names":["React","React","disabled","jsx","disabled","jsx"]}
package/dist/index.d.mts CHANGED
@@ -19,6 +19,11 @@ interface TypeLinkProps extends Omit<TypeTextProps, keyof Omit<React.ComponentPr
19
19
  };
20
20
  }
21
21
 
22
+ /**
23
+ * Link component. Automatically routes between the Tailwind implementation
24
+ * (preferred) and the styled-components implementation (for consumers using
25
+ * system/typography props or a styled() extension).
26
+ */
22
27
  declare const Link: React.ForwardRefExoticComponent<Omit<TypeLinkProps, "ref"> & React.RefAttributes<HTMLAnchorElement | HTMLButtonElement>>;
23
28
 
24
29
  export { Link, type TypeLinkProps, Link as default };
package/dist/index.d.ts CHANGED
@@ -19,6 +19,11 @@ interface TypeLinkProps extends Omit<TypeTextProps, keyof Omit<React.ComponentPr
19
19
  };
20
20
  }
21
21
 
22
+ /**
23
+ * Link component. Automatically routes between the Tailwind implementation
24
+ * (preferred) and the styled-components implementation (for consumers using
25
+ * system/typography props or a styled() extension).
26
+ */
22
27
  declare const Link: React.ForwardRefExoticComponent<Omit<TypeLinkProps, "ref"> & React.RefAttributes<HTMLAnchorElement | HTMLButtonElement>>;
23
28
 
24
29
  export { Link, type TypeLinkProps, Link as default };
package/dist/index.js CHANGED
@@ -36,7 +36,10 @@ __export(index_exports, {
36
36
  module.exports = __toCommonJS(index_exports);
37
37
 
38
38
  // src/Link.tsx
39
- var React = __toESM(require("react"));
39
+ var React3 = __toESM(require("react"));
40
+
41
+ // src/LinkHybrid.tsx
42
+ var React2 = __toESM(require("react"));
40
43
 
41
44
  // src/styles.ts
42
45
  var import_styled_components = __toESM(require("styled-components"));
@@ -85,9 +88,26 @@ var Container = (0, import_styled_components.default)(import_seeds_react_text.de
85
88
  `;
86
89
  var styles_default = Container;
87
90
 
88
- // src/Link.tsx
91
+ // src/LinkTailwind.tsx
92
+ var React = __toESM(require("react"));
89
93
  var import_jsx_runtime = require("react/jsx-runtime");
90
- var Link = React.forwardRef(
94
+ function cn(...inputs) {
95
+ const classes = [];
96
+ for (const input of inputs) {
97
+ if (!input) continue;
98
+ if (typeof input === "string") {
99
+ classes.push(input);
100
+ } else if (typeof input === "object") {
101
+ for (const [key, value] of Object.entries(input)) {
102
+ if (value) {
103
+ classes.push(key);
104
+ }
105
+ }
106
+ }
107
+ }
108
+ return classes.join(" ");
109
+ }
110
+ var LinkTailwind = React.forwardRef(
91
111
  ({
92
112
  href,
93
113
  external,
@@ -97,27 +117,32 @@ var Link = React.forwardRef(
97
117
  as,
98
118
  underline = true,
99
119
  qa = {},
120
+ className,
100
121
  ...rest
101
122
  }, ref) => {
102
- if (!href && external) {
103
- console.warn(
104
- "Warning: external prop cannot be set without a href declaration"
105
- );
106
- }
107
123
  const type = as || (href ? "a" : "button");
124
+ const Component = type;
125
+ const classes = cn(
126
+ "seeds-link",
127
+ {
128
+ "seeds-link-underline": !!underline,
129
+ "seeds-link-disabled": !!disabled2,
130
+ "seeds-link-no-href": !href
131
+ },
132
+ className
133
+ );
108
134
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
109
- styles_default,
135
+ Component,
110
136
  {
111
137
  ref,
112
138
  href,
113
139
  target: external ? "_blank" : void 0,
114
140
  type: type === "button" ? "button" : void 0,
115
141
  rel: external ? "noopener noreferrer" : void 0,
116
- forwardedAs: type,
117
142
  "aria-disabled": disabled2 ? disabled2 : void 0,
118
143
  disabled: disabled2,
119
144
  onClick,
120
- underline,
145
+ className: classes,
121
146
  "data-qa-link": "",
122
147
  "data-qa-link-isdisabled": disabled2 === true,
123
148
  ...qa,
@@ -127,11 +152,90 @@ var Link = React.forwardRef(
127
152
  );
128
153
  }
129
154
  );
155
+ LinkTailwind.displayName = "LinkTailwind";
156
+
157
+ // src/LinkHybrid.tsx
158
+ var import_seeds_react_system_props2 = require("@sproutsocial/seeds-react-system-props");
159
+ var import_jsx_runtime2 = require("react/jsx-runtime");
160
+ var TYPOGRAPHY_KEYS = [
161
+ "fontSize",
162
+ "typeScale",
163
+ "fontWeight",
164
+ "textAlign",
165
+ "lineHeight",
166
+ "isItalicized",
167
+ "fontFamily",
168
+ "fontStyle"
169
+ ];
170
+ var hasLinkStyledProps = (props) => (0, import_seeds_react_system_props2.hasStyledProps)(props) || TYPOGRAPHY_KEYS.some((key) => props[key] !== void 0);
171
+ var LinkHybrid = React2.forwardRef(
172
+ ({
173
+ href,
174
+ external,
175
+ children,
176
+ disabled: disabled2,
177
+ onClick,
178
+ as,
179
+ underline = true,
180
+ qa = {},
181
+ ...rest
182
+ }, ref) => {
183
+ if (!href && external) {
184
+ console.warn(
185
+ "Warning: external prop cannot be set without a href declaration"
186
+ );
187
+ }
188
+ const type = as || (href ? "a" : "button");
189
+ if (hasLinkStyledProps(rest)) {
190
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
191
+ styles_default,
192
+ {
193
+ ref,
194
+ href,
195
+ target: external ? "_blank" : void 0,
196
+ type: type === "button" ? "button" : void 0,
197
+ rel: external ? "noopener noreferrer" : void 0,
198
+ forwardedAs: type,
199
+ "aria-disabled": disabled2 ? disabled2 : void 0,
200
+ disabled: disabled2,
201
+ onClick,
202
+ underline,
203
+ "data-qa-link": "",
204
+ "data-qa-link-isdisabled": disabled2 === true,
205
+ ...qa,
206
+ ...rest,
207
+ children
208
+ }
209
+ );
210
+ }
211
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
212
+ LinkTailwind,
213
+ {
214
+ ref,
215
+ href,
216
+ external,
217
+ disabled: disabled2,
218
+ onClick,
219
+ as,
220
+ underline,
221
+ qa,
222
+ ...rest,
223
+ children
224
+ }
225
+ );
226
+ }
227
+ );
228
+ LinkHybrid.displayName = "Link";
229
+ var LinkHybrid_default = LinkHybrid;
230
+
231
+ // src/Link.tsx
232
+ var import_jsx_runtime3 = require("react/jsx-runtime");
233
+ var Link = React3.forwardRef((props, ref) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LinkHybrid_default, { ...props, ref }));
130
234
  Link.displayName = "Link";
131
235
  var Link_default = Link;
132
236
 
133
237
  // src/LinkTypes.ts
134
- var React2 = require("react");
238
+ var React4 = require("react");
135
239
 
136
240
  // src/constants.ts
137
241
  var import_seeds_color = require("@sproutsocial/seeds-color");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/Link.tsx","../src/styles.ts","../src/LinkTypes.ts","../src/constants.ts"],"sourcesContent":["import Link from \"./Link\";\n\nexport default Link;\nexport { Link };\nexport * from \"./LinkTypes\";\nexport * from \"./constants\";\n","import * as React from \"react\";\nimport Container from \"./styles\";\nimport type { TypeLinkProps } from \"./LinkTypes\";\n\nconst Link = React.forwardRef<\n HTMLAnchorElement | HTMLButtonElement,\n TypeLinkProps\n>(\n (\n {\n href,\n external,\n children,\n disabled,\n onClick,\n as,\n underline = true,\n qa = {},\n ...rest\n },\n ref\n ) => {\n if (!href && external) {\n // eslint-disable-next-line no-console\n console.warn(\n \"Warning: external prop cannot be set without a href declaration\"\n );\n }\n\n const type = as || (href ? \"a\" : \"button\");\n return (\n <Container\n ref={ref}\n href={href}\n target={external ? \"_blank\" : undefined}\n type={type === \"button\" ? \"button\" : undefined}\n rel={external ? \"noopener noreferrer\" : undefined}\n forwardedAs={type}\n aria-disabled={disabled ? disabled : undefined}\n disabled={disabled}\n onClick={onClick}\n underline={underline}\n data-qa-link=\"\"\n data-qa-link-isdisabled={disabled === true}\n {...qa}\n {...rest}\n >\n {children}\n </Container>\n );\n }\n);\n\nLink.displayName = \"Link\";\n\nexport default Link;\n","import styled, { css } from \"styled-components\";\nimport {\n TYPOGRAPHY,\n COMMON,\n FLEXBOX,\n} from \"@sproutsocial/seeds-react-system-props\";\nimport { focusRing, disabled } from \"@sproutsocial/seeds-react-mixins\";\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport type { TypeLinkProps } from \"./LinkTypes\";\n\nconst Container = styled(Text)<TypeLinkProps>`\n border: 0;\n font-family: ${(props) => props.theme.fontFamily};\n text-decoration: ${(props) => (props.underline ? \"underline\" : \"none\")};\n appearance: none;\n cursor: pointer;\n ${(props) =>\n props.disabled &&\n css`\n opacity: 0.4;\n cursor: not-allowed;\n `}\n font-weight: ${(props) => props.theme.fontWeights.semibold};\n color: ${(props) => props.theme.colors.link.base};\n\n &:hover {\n color: ${(props) => props.theme.colors.link.hover};\n text-decoration: underline;\n }\n\n &:active {\n color: ${(props) => props.theme.colors.link.hover};\n }\n\n &:focus {\n ${focusRing}\n }\n\n &:focus:active {\n box-shadow: none;\n }\n\n ${(props) =>\n !props.href &&\n css`\n background: none;\n `}\n\n ${(props) => props.disabled && disabled}\n\n ${COMMON}\n ${TYPOGRAPHY}\n ${FLEXBOX}\n`;\n\nexport default Container;\n","import * as React from \"react\";\nimport type { TypeStyledComponentsCommonProps } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeTextProps } from \"@sproutsocial/seeds-react-text\";\nimport type { TypeSystemFlexboxProps } from \"@sproutsocial/seeds-react-system-props\";\n\nexport interface TypeLinkProps\n extends Omit<\n TypeTextProps,\n keyof Omit<React.ComponentPropsWithoutRef<\"span\">, \"color\">\n >,\n Omit<React.ComponentPropsWithoutRef<\"button\">, \"color\">,\n TypeSystemFlexboxProps {\n /** Optional prop to make the URL open in a new tab */\n external?: boolean;\n children: React.ReactNode;\n\n /** Setting this prop will cause the component to be rendered as a link */\n href?: string;\n\n /** Disables user action and applies a disabled style to the component */\n disabled?: boolean;\n\n /** Can be used in addition to an href but still renders as a link. Omitting href will render as button */\n onClick?: (e: React.SyntheticEvent<HTMLButtonElement>) => void;\n as?: TypeStyledComponentsCommonProps[\"as\"];\n underline?: boolean;\n qa?: { [key: string]: unknown }; // should this be string|number?\n}\n","import { COLOR_BLUE_900 } from \"@sproutsocial/seeds-color\";\n\nconst defaultLink = {\n color: \"link\",\n hoverColor: \"link.hover\",\n activeColor: COLOR_BLUE_900,\n fontWeight: \"semibold\",\n};\n\nconst linkTheme = {\n default: defaultLink,\n};\n\nexport default linkTheme;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,YAAuB;;;ACAvB,+BAA4B;AAC5B,sCAIO;AACP,gCAAoC;AACpC,8BAAiB;AAGjB,IAAM,gBAAY,yBAAAA,SAAO,wBAAAC,OAAI;AAAA;AAAA,iBAEZ,CAAC,UAAU,MAAM,MAAM,UAAU;AAAA,qBAC7B,CAAC,UAAW,MAAM,YAAY,cAAc,MAAO;AAAA;AAAA;AAAA,IAGpE,CAAC,UACD,MAAM,YACN;AAAA;AAAA;AAAA,KAGC;AAAA,iBACY,CAAC,UAAU,MAAM,MAAM,YAAY,QAAQ;AAAA,WACjD,CAAC,UAAU,MAAM,MAAM,OAAO,KAAK,IAAI;AAAA;AAAA;AAAA,aAGrC,CAAC,UAAU,MAAM,MAAM,OAAO,KAAK,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,aAKxC,CAAC,UAAU,MAAM,MAAM,OAAO,KAAK,KAAK;AAAA;AAAA;AAAA;AAAA,MAI/C,mCAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOX,CAAC,UACD,CAAC,MAAM,QACP;AAAA;AAAA,KAEC;AAAA;AAAA,IAED,CAAC,UAAU,MAAM,YAAY,kCAAQ;AAAA;AAAA,KAEpC,sCAAM;AAAA,KACN,0CAAU;AAAA,KACV,uCAAO;AAAA;AAGZ,IAAO,iBAAQ;;;ADxBT;AA3BN,IAAM,OAAa;AAAA,EAIjB,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAAC;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,KAAK,CAAC;AAAA,IACN,GAAG;AAAA,EACL,GACA,QACG;AACH,QAAI,CAAC,QAAQ,UAAU;AAErB,cAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAEA,UAAM,OAAO,OAAO,OAAO,MAAM;AACjC,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,QAAQ,WAAW,WAAW;AAAA,QAC9B,MAAM,SAAS,WAAW,WAAW;AAAA,QACrC,KAAK,WAAW,wBAAwB;AAAA,QACxC,aAAa;AAAA,QACb,iBAAeA,YAAWA,YAAW;AAAA,QACrC,UAAUA;AAAA,QACV;AAAA,QACA;AAAA,QACA,gBAAa;AAAA,QACb,2BAAyBA,cAAa;AAAA,QACrC,GAAG;AAAA,QACH,GAAG;AAAA,QAEH;AAAA;AAAA,IACH;AAAA,EAEJ;AACF;AAEA,KAAK,cAAc;AAEnB,IAAO,eAAQ;;;AEvDf,IAAAC,SAAuB;;;ACAvB,yBAA+B;;;AJE/B,IAAO,gBAAQ;","names":["styled","Text","disabled","React"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/Link.tsx","../src/LinkHybrid.tsx","../src/styles.ts","../src/LinkTailwind.tsx","../src/LinkTypes.ts","../src/constants.ts"],"sourcesContent":["import Link from \"./Link\";\n\nexport default Link;\nexport { Link };\nexport * from \"./LinkTypes\";\nexport * from \"./constants\";\n","import * as React from \"react\";\nimport LinkHybrid from \"./LinkHybrid\";\nimport type { TypeLinkProps } from \"./LinkTypes\";\n\n/**\n * Link component. Automatically routes between the Tailwind implementation\n * (preferred) and the styled-components implementation (for consumers using\n * system/typography props or a styled() extension).\n */\nconst Link = React.forwardRef<\n HTMLAnchorElement | HTMLButtonElement,\n TypeLinkProps\n>((props, ref) => <LinkHybrid {...props} ref={ref} />);\n\nLink.displayName = \"Link\";\n\nexport default Link;\n","/**\n * Hybrid Link Component\n * Automatically chooses between Tailwind and styled-components based on props.\n *\n * Link's underlying Container is `styled(Text)`, so it accepts typography props\n * (e.g. `fontSize`). `hasStyledProps` does not include typography props, so we\n * additionally route to the styled-components path when any typography prop is\n * present — mirroring Text — so font sizing is never silently dropped.\n */\n\nimport * as React from \"react\";\nimport Container from \"./styles\"; // Styled-components version\nimport { LinkTailwind } from \"./LinkTailwind\"; // Tailwind version\nimport { hasStyledProps } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeLinkProps } from \"./LinkTypes\";\n\nconst TYPOGRAPHY_KEYS = [\n \"fontSize\",\n \"typeScale\",\n \"fontWeight\",\n \"textAlign\",\n \"lineHeight\",\n \"isItalicized\",\n \"fontFamily\",\n \"fontStyle\",\n] as const;\n\nconst hasLinkStyledProps = (props: Record<string, unknown>): boolean =>\n hasStyledProps(props) ||\n TYPOGRAPHY_KEYS.some((key) => props[key] !== undefined);\n\nconst LinkHybrid = React.forwardRef<\n HTMLAnchorElement | HTMLButtonElement,\n TypeLinkProps\n>(\n (\n {\n href,\n external,\n children,\n disabled,\n onClick,\n as,\n underline = true,\n qa = {},\n ...rest\n },\n ref\n ) => {\n if (!href && external) {\n // eslint-disable-next-line no-console\n console.warn(\n \"Warning: external prop cannot be set without a href declaration\"\n );\n }\n\n const type = as || (href ? \"a\" : \"button\");\n\n if (hasLinkStyledProps(rest)) {\n return (\n <Container\n ref={ref}\n href={href}\n target={external ? \"_blank\" : undefined}\n type={type === \"button\" ? \"button\" : undefined}\n rel={external ? \"noopener noreferrer\" : undefined}\n forwardedAs={type}\n aria-disabled={disabled ? disabled : undefined}\n disabled={disabled}\n onClick={onClick}\n underline={underline}\n data-qa-link=\"\"\n data-qa-link-isdisabled={disabled === true}\n {...qa}\n {...rest}\n >\n {children}\n </Container>\n );\n }\n\n // Use Tailwind version (preferred - better performance)\n return (\n <LinkTailwind\n ref={ref}\n href={href}\n external={external}\n disabled={disabled}\n onClick={onClick}\n as={as}\n underline={underline}\n qa={qa}\n {...rest}\n >\n {children}\n </LinkTailwind>\n );\n }\n);\n\nLinkHybrid.displayName = \"Link\";\n\nexport default LinkHybrid;\n","import styled, { css } from \"styled-components\";\nimport {\n TYPOGRAPHY,\n COMMON,\n FLEXBOX,\n} from \"@sproutsocial/seeds-react-system-props\";\nimport { focusRing, disabled } from \"@sproutsocial/seeds-react-mixins\";\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport type { TypeLinkProps } from \"./LinkTypes\";\n\nconst Container = styled(Text)<TypeLinkProps>`\n border: 0;\n font-family: ${(props) => props.theme.fontFamily};\n text-decoration: ${(props) => (props.underline ? \"underline\" : \"none\")};\n appearance: none;\n cursor: pointer;\n ${(props) =>\n props.disabled &&\n css`\n opacity: 0.4;\n cursor: not-allowed;\n `}\n font-weight: ${(props) => props.theme.fontWeights.semibold};\n color: ${(props) => props.theme.colors.link.base};\n\n &:hover {\n color: ${(props) => props.theme.colors.link.hover};\n text-decoration: underline;\n }\n\n &:active {\n color: ${(props) => props.theme.colors.link.hover};\n }\n\n &:focus {\n ${focusRing}\n }\n\n &:focus:active {\n box-shadow: none;\n }\n\n ${(props) =>\n !props.href &&\n css`\n background: none;\n `}\n\n ${(props) => props.disabled && disabled}\n\n ${COMMON}\n ${TYPOGRAPHY}\n ${FLEXBOX}\n`;\n\nexport default Container;\n","/**\n * Tailwind CSS implementation of Link component\n * Uses Seeds link CSS classes from link.css\n */\n\nimport * as React from \"react\";\nimport type { TypeLinkProps } from \"./LinkTypes\";\n\n// Utility for merging class names properly\nfunction cn(\n ...inputs: (string | undefined | null | false | Record<string, boolean>)[]\n): string {\n const classes: string[] = [];\n\n for (const input of inputs) {\n if (!input) continue;\n\n if (typeof input === \"string\") {\n classes.push(input);\n } else if (typeof input === \"object\") {\n for (const [key, value] of Object.entries(input)) {\n if (value) {\n classes.push(key);\n }\n }\n }\n }\n\n return classes.join(\" \");\n}\n\nexport const LinkTailwind = React.forwardRef<\n HTMLAnchorElement | HTMLButtonElement,\n TypeLinkProps\n>(\n (\n {\n href,\n external,\n children,\n disabled,\n onClick,\n as,\n underline = true,\n qa = {},\n className,\n ...rest\n },\n ref\n ) => {\n const type = as || (href ? \"a\" : \"button\");\n const Component = type as any;\n\n const classes = cn(\n \"seeds-link\",\n {\n \"seeds-link-underline\": !!underline,\n \"seeds-link-disabled\": !!disabled,\n \"seeds-link-no-href\": !href,\n },\n className\n );\n\n return (\n <Component\n ref={ref}\n href={href}\n target={external ? \"_blank\" : undefined}\n type={type === \"button\" ? \"button\" : undefined}\n rel={external ? \"noopener noreferrer\" : undefined}\n aria-disabled={disabled ? disabled : undefined}\n disabled={disabled}\n onClick={onClick}\n className={classes}\n data-qa-link=\"\"\n data-qa-link-isdisabled={disabled === true}\n {...qa}\n {...rest}\n >\n {children}\n </Component>\n );\n }\n);\n\nLinkTailwind.displayName = \"LinkTailwind\";\n","import * as React from \"react\";\nimport type { TypeStyledComponentsCommonProps } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeTextProps } from \"@sproutsocial/seeds-react-text\";\nimport type { TypeSystemFlexboxProps } from \"@sproutsocial/seeds-react-system-props\";\n\nexport interface TypeLinkProps\n extends Omit<\n TypeTextProps,\n keyof Omit<React.ComponentPropsWithoutRef<\"span\">, \"color\">\n >,\n Omit<React.ComponentPropsWithoutRef<\"button\">, \"color\">,\n TypeSystemFlexboxProps {\n /** Optional prop to make the URL open in a new tab */\n external?: boolean;\n children: React.ReactNode;\n\n /** Setting this prop will cause the component to be rendered as a link */\n href?: string;\n\n /** Disables user action and applies a disabled style to the component */\n disabled?: boolean;\n\n /** Can be used in addition to an href but still renders as a link. Omitting href will render as button */\n onClick?: (e: React.SyntheticEvent<HTMLButtonElement>) => void;\n as?: TypeStyledComponentsCommonProps[\"as\"];\n underline?: boolean;\n qa?: { [key: string]: unknown }; // should this be string|number?\n}\n","import { COLOR_BLUE_900 } from \"@sproutsocial/seeds-color\";\n\nconst defaultLink = {\n color: \"link\",\n hoverColor: \"link.hover\",\n activeColor: COLOR_BLUE_900,\n fontWeight: \"semibold\",\n};\n\nconst linkTheme = {\n default: defaultLink,\n};\n\nexport default linkTheme;\n"],"mappings":"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","names":["React","React","styled","Text","disabled","import_seeds_react_system_props","import_jsx_runtime","disabled","import_jsx_runtime","React"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sproutsocial/seeds-react-link",
3
- "version": "1.1.6",
3
+ "version": "1.1.12",
4
4
  "description": "Seeds React Link",
5
5
  "author": "Sprout Social, Inc.",
6
6
  "license": "MIT",
@@ -18,10 +18,10 @@
18
18
  "test:watch": "jest --watch --coverage=false"
19
19
  },
20
20
  "dependencies": {
21
- "@sproutsocial/seeds-react-theme": "^3.6.2",
22
- "@sproutsocial/seeds-react-system-props": "^3.0.1",
23
- "@sproutsocial/seeds-react-mixins": "^4.3.3",
24
- "@sproutsocial/seeds-react-text": "^1.4.0",
21
+ "@sproutsocial/seeds-react-theme": "^4.1.0",
22
+ "@sproutsocial/seeds-react-system-props": "^3.1.1",
23
+ "@sproutsocial/seeds-react-mixins": "^4.3.7",
24
+ "@sproutsocial/seeds-react-text": "^1.4.3",
25
25
  "@sproutsocial/seeds-color": "^2.3.0"
26
26
  },
27
27
  "devDependencies": {
@@ -35,8 +35,8 @@
35
35
  "@sproutsocial/seeds-tsconfig": "*",
36
36
  "@sproutsocial/seeds-testing": "*",
37
37
  "@sproutsocial/seeds-react-testing-library": "*",
38
- "@sproutsocial/seeds-react-icon": "^2.3.2",
39
- "@sproutsocial/seeds-react-box": "^1.1.16"
38
+ "@sproutsocial/seeds-react-icon": "^2.4.0",
39
+ "@sproutsocial/seeds-react-box": "^1.1.21"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "styled-components": "^5.2.3"
@@ -99,3 +99,20 @@ export const DecorativeBackgrounds: Story = {
99
99
  />
100
100
  ),
101
101
  };
102
+
103
+ /**
104
+ * Demonstrates that Tailwind utility classes passed via `className` override the
105
+ * component's own CSS. Because `link.css` lives in `@layer components`, the
106
+ * `text-[#FF6B00]` utility wins the cascade and recolors the link text orange,
107
+ * overriding the component's default blue link color. Passing only `className`
108
+ * (no typography/system props) routes the Link to its Tailwind path so the
109
+ * override applies.
110
+ */
111
+ export const TailwindOverrides: Story = {
112
+ render: () => (
113
+ <Link href="#tailwind-override" className="text-[#FF6B00]">
114
+ Tailwind utilities override the component CSS
115
+ </Link>
116
+ ),
117
+ name: "🚀 Tailwind class overrides",
118
+ };
package/src/Link.tsx CHANGED
@@ -1,55 +1,16 @@
1
1
  import * as React from "react";
2
- import Container from "./styles";
2
+ import LinkHybrid from "./LinkHybrid";
3
3
  import type { TypeLinkProps } from "./LinkTypes";
4
4
 
5
+ /**
6
+ * Link component. Automatically routes between the Tailwind implementation
7
+ * (preferred) and the styled-components implementation (for consumers using
8
+ * system/typography props or a styled() extension).
9
+ */
5
10
  const Link = React.forwardRef<
6
11
  HTMLAnchorElement | HTMLButtonElement,
7
12
  TypeLinkProps
8
- >(
9
- (
10
- {
11
- href,
12
- external,
13
- children,
14
- disabled,
15
- onClick,
16
- as,
17
- underline = true,
18
- qa = {},
19
- ...rest
20
- },
21
- ref
22
- ) => {
23
- if (!href && external) {
24
- // eslint-disable-next-line no-console
25
- console.warn(
26
- "Warning: external prop cannot be set without a href declaration"
27
- );
28
- }
29
-
30
- const type = as || (href ? "a" : "button");
31
- return (
32
- <Container
33
- ref={ref}
34
- href={href}
35
- target={external ? "_blank" : undefined}
36
- type={type === "button" ? "button" : undefined}
37
- rel={external ? "noopener noreferrer" : undefined}
38
- forwardedAs={type}
39
- aria-disabled={disabled ? disabled : undefined}
40
- disabled={disabled}
41
- onClick={onClick}
42
- underline={underline}
43
- data-qa-link=""
44
- data-qa-link-isdisabled={disabled === true}
45
- {...qa}
46
- {...rest}
47
- >
48
- {children}
49
- </Container>
50
- );
51
- }
52
- );
13
+ >((props, ref) => <LinkHybrid {...props} ref={ref} />);
53
14
 
54
15
  Link.displayName = "Link";
55
16
 
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Hybrid Link Component
3
+ * Automatically chooses between Tailwind and styled-components based on props.
4
+ *
5
+ * Link's underlying Container is `styled(Text)`, so it accepts typography props
6
+ * (e.g. `fontSize`). `hasStyledProps` does not include typography props, so we
7
+ * additionally route to the styled-components path when any typography prop is
8
+ * present — mirroring Text — so font sizing is never silently dropped.
9
+ */
10
+
11
+ import * as React from "react";
12
+ import Container from "./styles"; // Styled-components version
13
+ import { LinkTailwind } from "./LinkTailwind"; // Tailwind version
14
+ import { hasStyledProps } from "@sproutsocial/seeds-react-system-props";
15
+ import type { TypeLinkProps } from "./LinkTypes";
16
+
17
+ const TYPOGRAPHY_KEYS = [
18
+ "fontSize",
19
+ "typeScale",
20
+ "fontWeight",
21
+ "textAlign",
22
+ "lineHeight",
23
+ "isItalicized",
24
+ "fontFamily",
25
+ "fontStyle",
26
+ ] as const;
27
+
28
+ const hasLinkStyledProps = (props: Record<string, unknown>): boolean =>
29
+ hasStyledProps(props) ||
30
+ TYPOGRAPHY_KEYS.some((key) => props[key] !== undefined);
31
+
32
+ const LinkHybrid = React.forwardRef<
33
+ HTMLAnchorElement | HTMLButtonElement,
34
+ TypeLinkProps
35
+ >(
36
+ (
37
+ {
38
+ href,
39
+ external,
40
+ children,
41
+ disabled,
42
+ onClick,
43
+ as,
44
+ underline = true,
45
+ qa = {},
46
+ ...rest
47
+ },
48
+ ref
49
+ ) => {
50
+ if (!href && external) {
51
+ // eslint-disable-next-line no-console
52
+ console.warn(
53
+ "Warning: external prop cannot be set without a href declaration"
54
+ );
55
+ }
56
+
57
+ const type = as || (href ? "a" : "button");
58
+
59
+ if (hasLinkStyledProps(rest)) {
60
+ return (
61
+ <Container
62
+ ref={ref}
63
+ href={href}
64
+ target={external ? "_blank" : undefined}
65
+ type={type === "button" ? "button" : undefined}
66
+ rel={external ? "noopener noreferrer" : undefined}
67
+ forwardedAs={type}
68
+ aria-disabled={disabled ? disabled : undefined}
69
+ disabled={disabled}
70
+ onClick={onClick}
71
+ underline={underline}
72
+ data-qa-link=""
73
+ data-qa-link-isdisabled={disabled === true}
74
+ {...qa}
75
+ {...rest}
76
+ >
77
+ {children}
78
+ </Container>
79
+ );
80
+ }
81
+
82
+ // Use Tailwind version (preferred - better performance)
83
+ return (
84
+ <LinkTailwind
85
+ ref={ref}
86
+ href={href}
87
+ external={external}
88
+ disabled={disabled}
89
+ onClick={onClick}
90
+ as={as}
91
+ underline={underline}
92
+ qa={qa}
93
+ {...rest}
94
+ >
95
+ {children}
96
+ </LinkTailwind>
97
+ );
98
+ }
99
+ );
100
+
101
+ LinkHybrid.displayName = "Link";
102
+
103
+ export default LinkHybrid;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Tailwind CSS implementation of Link component
3
+ * Uses Seeds link CSS classes from link.css
4
+ */
5
+
6
+ import * as React from "react";
7
+ import type { TypeLinkProps } from "./LinkTypes";
8
+
9
+ // Utility for merging class names properly
10
+ function cn(
11
+ ...inputs: (string | undefined | null | false | Record<string, boolean>)[]
12
+ ): string {
13
+ const classes: string[] = [];
14
+
15
+ for (const input of inputs) {
16
+ if (!input) continue;
17
+
18
+ if (typeof input === "string") {
19
+ classes.push(input);
20
+ } else if (typeof input === "object") {
21
+ for (const [key, value] of Object.entries(input)) {
22
+ if (value) {
23
+ classes.push(key);
24
+ }
25
+ }
26
+ }
27
+ }
28
+
29
+ return classes.join(" ");
30
+ }
31
+
32
+ export const LinkTailwind = React.forwardRef<
33
+ HTMLAnchorElement | HTMLButtonElement,
34
+ TypeLinkProps
35
+ >(
36
+ (
37
+ {
38
+ href,
39
+ external,
40
+ children,
41
+ disabled,
42
+ onClick,
43
+ as,
44
+ underline = true,
45
+ qa = {},
46
+ className,
47
+ ...rest
48
+ },
49
+ ref
50
+ ) => {
51
+ const type = as || (href ? "a" : "button");
52
+ const Component = type as any;
53
+
54
+ const classes = cn(
55
+ "seeds-link",
56
+ {
57
+ "seeds-link-underline": !!underline,
58
+ "seeds-link-disabled": !!disabled,
59
+ "seeds-link-no-href": !href,
60
+ },
61
+ className
62
+ );
63
+
64
+ return (
65
+ <Component
66
+ ref={ref}
67
+ href={href}
68
+ target={external ? "_blank" : undefined}
69
+ type={type === "button" ? "button" : undefined}
70
+ rel={external ? "noopener noreferrer" : undefined}
71
+ aria-disabled={disabled ? disabled : undefined}
72
+ disabled={disabled}
73
+ onClick={onClick}
74
+ className={classes}
75
+ data-qa-link=""
76
+ data-qa-link-isdisabled={disabled === true}
77
+ {...qa}
78
+ {...rest}
79
+ >
80
+ {children}
81
+ </Component>
82
+ );
83
+ }
84
+ );
85
+
86
+ LinkTailwind.displayName = "LinkTailwind";
@@ -102,11 +102,10 @@ describe("Racine Link", () => {
102
102
  });
103
103
 
104
104
  it("Can render with an underline", () => {
105
+ // The Tailwind path renders the link with the `seeds-link-underline`
106
+ // class, which sets `text-decoration: underline` in link.css.
105
107
  render(<Link underline>Link</Link>);
106
- expect(screen.getByText("Link")).toHaveStyleRule(
107
- "text-decoration",
108
- "underline"
109
- );
108
+ expect(screen.getByText("Link")).toHaveClass("seeds-link-underline");
110
109
  });
111
110
  });
112
111
 
@@ -0,0 +1,55 @@
1
+ import React from "react";
2
+ import { render, screen } from "@sproutsocial/seeds-react-testing-library";
3
+ import Link from "../Link";
4
+
5
+ describe("Link Tailwind path", () => {
6
+ it("renders with the seeds-link class when no styled props are used", () => {
7
+ render(<Link href="/test">Tailwind Link</Link>);
8
+ const el = screen.getByText("Tailwind Link");
9
+ expect(el.tagName).toBe("A");
10
+ expect(el).toHaveClass("seeds-link");
11
+ });
12
+
13
+ it("applies the disabled class when disabled", () => {
14
+ render(<Link disabled>Disabled</Link>);
15
+ expect(screen.getByText("Disabled")).toHaveClass("seeds-link-disabled");
16
+ });
17
+
18
+ it("forwards a consumer className (styled() extension passthrough)", () => {
19
+ render(
20
+ <Link href="/test" className="sc-extension">
21
+ Class Link
22
+ </Link>
23
+ );
24
+ const el = screen.getByText("Class Link");
25
+ expect(el).toHaveClass("seeds-link");
26
+ expect(el).toHaveClass("sc-extension");
27
+ });
28
+
29
+ it("routes typography props (fontSize) to the styled-components path", () => {
30
+ render(
31
+ <Link href="/test" fontSize={300}>
32
+ Sized Link
33
+ </Link>
34
+ );
35
+ expect(screen.getByText("Sized Link")).not.toHaveClass("seeds-link");
36
+ });
37
+
38
+ it("routes fontFamily to the styled-components path", () => {
39
+ render(
40
+ <Link href="/test" fontFamily="mono">
41
+ Mono Link
42
+ </Link>
43
+ );
44
+ expect(screen.getByText("Mono Link")).not.toHaveClass("seeds-link");
45
+ });
46
+
47
+ it("routes fontStyle to the styled-components path", () => {
48
+ render(
49
+ <Link href="/test" fontStyle="italic">
50
+ Italic Link
51
+ </Link>
52
+ );
53
+ expect(screen.getByText("Italic Link")).not.toHaveClass("seeds-link");
54
+ });
55
+ });
package/src/link.css ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Seeds Link component classes
3
+ * Use these instead of writing out individual Tailwind utility classes.
4
+ *
5
+ * Requires @sproutsocial/seeds-react-theme/dist/theme-all.css imported for
6
+ * CSS variable definitions and dark mode support.
7
+ *
8
+ * Rules live in the Tailwind `components` layer so consumer utility classes
9
+ * (e.g. mx-200, p-300, inline-flex) win the cascade over these defaults.
10
+ */
11
+
12
+ @layer components {
13
+ .seeds-link {
14
+ border: 0;
15
+ appearance: none;
16
+ cursor: pointer;
17
+ font-family: var(--font-family);
18
+ font-weight: var(--font-weight-semibold);
19
+ color: var(--color-link-base);
20
+ text-decoration: none;
21
+ }
22
+
23
+ .seeds-link-underline {
24
+ text-decoration: underline;
25
+ }
26
+
27
+ .seeds-link:hover {
28
+ color: var(--color-link-hover);
29
+ text-decoration: underline;
30
+ }
31
+
32
+ .seeds-link:active {
33
+ color: var(--color-link-hover);
34
+ }
35
+
36
+ .seeds-link:focus {
37
+ outline: none;
38
+ box-shadow:
39
+ 0 0 0 1px var(--color-button-primary-bg-base),
40
+ 0 0 0 4px color-mix(in srgb, var(--color-button-primary-bg-base) 30%, transparent);
41
+ }
42
+
43
+ .seeds-link:focus:active {
44
+ box-shadow: none;
45
+ }
46
+
47
+ .seeds-link-disabled {
48
+ opacity: 0.4;
49
+ cursor: not-allowed;
50
+ pointer-events: none;
51
+ }
52
+
53
+ /* When rendered as a button (no href) remove the native button background */
54
+ .seeds-link-no-href {
55
+ background: none;
56
+ }
57
+ }