@descope-ui/descope-link 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
+
5
+ ## 0.0.1 (2025-07-03)
6
+
7
+ ### Dependency Updates
8
+
9
+ * `e2e-utils` updated to version `0.0.1`
10
+ * `@descope-ui/descope-text` updated to version `0.0.17`
11
+ * `@descope-ui/common` updated to version `0.0.16`
12
+ * `@descope-ui/theme-globals` updated to version `0.0.17`
13
+ # Changelog
@@ -0,0 +1,61 @@
1
+ import { test, expect } from '@playwright/test';
2
+ import { getStoryUrl, loopConfig } from 'e2e-utils';
3
+
4
+ const MOCK_URL = 'https://www.descope.com/';
5
+
6
+ const componentAttributes = {
7
+ text: 'Test Text',
8
+ variant: ['h1', 'h2', 'h3', 'subtitle1', 'subtitle2', 'body1', 'body2'],
9
+ mode: ['primary', 'secondary', 'success', 'error'],
10
+ tooltip: 'Tooltip',
11
+ 'text-align': ['left', 'center', 'right'],
12
+ 'full-width': ['true', 'false'],
13
+ };
14
+
15
+ const storyName = 'descope-link';
16
+ const componentName = 'descope-link';
17
+
18
+ test.describe('theme', () => {
19
+ loopConfig(componentAttributes, (attr, value) => {
20
+ test(`${attr}: ${value}`, async ({ page }) => {
21
+ // we're running all tests with default full-width to allow text-align tests to run properly
22
+ await page.goto(getStoryUrl(storyName, { 'full-width': true, [attr]: value }), {
23
+ waitUntil: 'networkidle',
24
+ });
25
+ const component = page.locator(componentName);
26
+ expect(await component.screenshot()).toMatchSnapshot();
27
+ });
28
+ });
29
+
30
+ test(`direction: rtl`, async ({ page }) => {
31
+ await page.goto(
32
+ getStoryUrl(storyName, { direction: 'rtl', text: '-Hello World', 'full-width': true })
33
+ );
34
+ const component = page.locator(componentName);
35
+ expect(await component.screenshot()).toMatchSnapshot();
36
+ });
37
+ });
38
+
39
+ test.describe('logic', () => {
40
+ test(`href`, async ({ page }) => {
41
+ await page.goto(getStoryUrl(storyName, { href: MOCK_URL }), { waitUntil: 'networkidle' });
42
+ await page.waitForSelector(componentName);
43
+ page.locator(componentName).click();
44
+ await page.waitForURL(MOCK_URL);
45
+ });
46
+
47
+ test('target', async ({ page, context }) => {
48
+ await page.goto(getStoryUrl(storyName, { href: MOCK_URL, target: '_blank' }), {
49
+ waitUntil: 'networkidle',
50
+ });
51
+
52
+ const [newPage] = await Promise.all([
53
+ context.waitForEvent('page'),
54
+ page.locator(componentName).first().click(),
55
+ ]);
56
+
57
+ await newPage.waitForLoadState();
58
+
59
+ expect(newPage.url()).toBe(MOCK_URL);
60
+ });
61
+ });
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@descope-ui/descope-link",
3
+ "version": "0.0.1",
4
+ "exports": {
5
+ ".": {
6
+ "import": "./src/component/index.js"
7
+ },
8
+ "./theme": {
9
+ "import": "./src/theme.js"
10
+ },
11
+ "./class": {
12
+ "import": "./src/component/LinkClass.js"
13
+ }
14
+ },
15
+ "devDependencies": {
16
+ "@playwright/test": "1.38.1",
17
+ "e2e-utils": "0.0.1",
18
+ "@descope-ui/descope-text": "0.0.17"
19
+ },
20
+ "dependencies": {
21
+ "@descope-ui/common": "0.0.16",
22
+ "@descope-ui/theme-globals": "0.0.17"
23
+ },
24
+ "publishConfig": {
25
+ "link-workspace-packages": false
26
+ },
27
+ "scripts": {
28
+ "test": "echo 'No tests defined' && exit 0",
29
+ "test:e2e": "echo 'No e2e tests defined' && exit 0"
30
+ }
31
+ }
package/project.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@descope-ui/descope-link",
3
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "packages/web-components/components/descope-link/src",
5
+ "projectType": "library",
6
+ "targets": {
7
+ "version": {
8
+ "executor": "@jscutlery/semver:version",
9
+ "options": {
10
+ "trackDeps": true,
11
+ "push": false,
12
+ "preset": "conventional"
13
+ }
14
+ }
15
+ },
16
+ "tags": []
17
+ }
@@ -0,0 +1,83 @@
1
+ import {
2
+ createStyleMixin,
3
+ draggableMixin,
4
+ componentNameValidationMixin,
5
+ } from '@descope-ui/common/components-mixins';
6
+ import { compose } from '@descope-ui/common/utils';
7
+ import {
8
+ getComponentName,
9
+ forwardAttrs,
10
+ injectStyle,
11
+ } from '@descope-ui/common/components-helpers';
12
+ import { createBaseClass } from '@descope-ui/common/base-classes';
13
+ import { TextClass } from '@descope-ui/descope-text/class';
14
+
15
+ export const componentName = getComponentName('link');
16
+
17
+ class RawLink extends createBaseClass({ componentName, baseSelector: ':host a' }) {
18
+ constructor() {
19
+ super();
20
+
21
+ this.attachShadow({ mode: 'open' }).innerHTML = `
22
+ <div>
23
+ <descope-text>
24
+ <a>
25
+ <slot></slot>
26
+ </a>
27
+ </descope-text>
28
+ </div>
29
+ `;
30
+
31
+ injectStyle(
32
+ `
33
+ :host {
34
+ display: inline-block;
35
+ line-height: 1em;
36
+ }
37
+ :host a {
38
+ display: inline;
39
+ }
40
+ `,
41
+ this
42
+ );
43
+
44
+ forwardAttrs(this, this.shadowRoot.querySelector('a'), {
45
+ includeAttrs: ['href', 'target', 'tooltip'],
46
+ mapAttrs: {
47
+ tooltip: 'title',
48
+ },
49
+ });
50
+
51
+ forwardAttrs(this, this.shadowRoot.querySelector('descope-text'), {
52
+ includeAttrs: ['mode', 'variant'],
53
+ });
54
+ }
55
+ }
56
+
57
+ const selectors = {
58
+ host: { selector: () => ':host' },
59
+ link: { selector: () => ':host a' },
60
+ anchor: {},
61
+ wrapper: { selector: () => ':host > div' },
62
+ text: { selector: () => TextClass.componentName },
63
+ };
64
+
65
+ const { anchor, text, host, wrapper, link } = selectors;
66
+
67
+ export const LinkClass = compose(
68
+ createStyleMixin({
69
+ mappings: {
70
+ hostWidth: { ...host, property: 'width' },
71
+ hostDirection: { ...text, property: 'direction' },
72
+ textAlign: wrapper,
73
+ textDecoration: { ...link, property: 'text-decoration', fallback: 'none' },
74
+ textColor: [
75
+ { ...anchor, property: 'color' },
76
+ { ...text, property: TextClass.cssVarList.textColor },
77
+ ],
78
+ cursor: anchor,
79
+ },
80
+ }),
81
+ draggableMixin,
82
+ componentNameValidationMixin
83
+ )(RawLink);
@@ -0,0 +1,6 @@
1
+ import { componentName, LinkClass } from './LinkClass';
2
+ import '@descope-ui/descope-text';
3
+
4
+ customElements.define(componentName, LinkClass);
5
+
6
+ export { LinkClass, componentName };
package/src/theme.js ADDED
@@ -0,0 +1,36 @@
1
+ import globals from '@descope-ui/theme-globals';
2
+ import { getThemeRefs } from '@descope-ui/common/theme-helpers';
3
+ import { LinkClass } from './component/LinkClass';
4
+
5
+ const globalRefs = getThemeRefs(globals);
6
+ const vars = LinkClass.cssVarList;
7
+
8
+ const link = {
9
+ [vars.hostDirection]: globalRefs.direction,
10
+ [vars.cursor]: 'pointer',
11
+
12
+ [vars.textColor]: globalRefs.colors.primary.main,
13
+
14
+ textAlign: {
15
+ right: { [vars.textAlign]: 'right' },
16
+ left: { [vars.textAlign]: 'left' },
17
+ center: { [vars.textAlign]: 'center' },
18
+ },
19
+
20
+ _fullWidth: {
21
+ [vars.hostWidth]: '100%',
22
+ },
23
+
24
+ _hover: {
25
+ [vars.textDecoration]: 'underline',
26
+ },
27
+
28
+ mode: {
29
+ secondary: {
30
+ [vars.textColor]: globalRefs.colors.secondary.main,
31
+ },
32
+ },
33
+ };
34
+
35
+ export default link;
36
+ export { vars };
@@ -0,0 +1,70 @@
1
+ import { componentName } from '../src/component';
2
+ import {
3
+ textContentControl,
4
+ textAlignControl,
5
+ modeControl,
6
+ fullWidthControl,
7
+ directionControl,
8
+ } from '@descope-ui/common/sb-controls';
9
+
10
+ const Template = ({
11
+ variant,
12
+ mode,
13
+ href,
14
+ target,
15
+ 'text-align': textAlign,
16
+ 'full-width': fullWidth,
17
+ text,
18
+ direction,
19
+ }) => `
20
+ <descope-link
21
+ mode="${mode}"
22
+ variant="${variant}"
23
+ href="${href || ''}"
24
+ target="${target || ''}"
25
+ text-align="${textAlign || ''}"
26
+ full-width="${fullWidth || false}"
27
+ st-host-direction="${direction ?? ''}"
28
+ >
29
+ ${text}
30
+ </descope-link>
31
+ `;
32
+
33
+ export default {
34
+ component: componentName,
35
+ title: 'descope-link',
36
+ parameters: {
37
+ panelPosition: 'right',
38
+ controls: { expanded: true },
39
+ },
40
+ argTypes: {
41
+ ...textContentControl,
42
+ ...modeControl,
43
+ ...textAlignControl,
44
+ ...fullWidthControl,
45
+ ...directionControl,
46
+ variant: {
47
+ name: 'Variant',
48
+ options: ['h1', 'h2', 'h3', 'subtitle1', 'subtitle2', 'body1', 'body2'],
49
+ control: { type: 'select' },
50
+ },
51
+ href: {
52
+ name: 'Link',
53
+ control: { type: 'text' },
54
+ },
55
+ target: {
56
+ name: 'Target',
57
+ options: ['', '_blank'],
58
+ control: { type: 'select' },
59
+ },
60
+ },
61
+ };
62
+
63
+ export const Default = Template.bind({});
64
+
65
+ Default.args = {
66
+ text: 'Link',
67
+ variant: 'h1',
68
+ mode: 'primary',
69
+ href: 'https://descope.com',
70
+ };