@cfasim-ui/components 0.1.9 → 0.1.10
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/dist/Box/Box.d.ts +24 -0
- package/dist/Box/Box.spec.d.ts +1 -0
- package/dist/Box/Box.test.d.ts +1 -0
- package/dist/Button/Button.d.ts +29 -0
- package/dist/Button/Button.spec.d.ts +1 -0
- package/dist/Button/Button.test.d.ts +1 -0
- package/dist/Expander/Expander.d.ts +28 -0
- package/dist/Expander/Expander.spec.d.ts +1 -0
- package/dist/Hint/Hint.d.ts +5 -0
- package/dist/Hint/Hint.spec.d.ts +1 -0
- package/dist/Hint/Hint.test.d.ts +1 -0
- package/dist/Icon/Icon.d.ts +18 -0
- package/dist/Icon/Icon.spec.d.ts +1 -0
- package/dist/LightDarkToggle/LightDarkToggle.d.ts +2 -0
- package/dist/NumberInput/NumberInput.d.ts +21 -0
- package/dist/NumberInput/NumberInput.spec.d.ts +1 -0
- package/dist/NumberInput/NumberInput.test.d.ts +1 -0
- package/dist/SelectBox/SelectBox.d.ts +19 -0
- package/dist/SelectBox/SelectBox.spec.d.ts +1 -0
- package/dist/SelectBox/SelectBox.test.d.ts +1 -0
- package/dist/SidebarLayout/SidebarLayout.d.ts +37 -0
- package/dist/SidebarLayout/SidebarLayout.test.d.ts +1 -0
- package/dist/Spinner/Spinner.d.ts +9 -0
- package/dist/Spinner/Spinner.spec.d.ts +1 -0
- package/dist/TextInput/TextInput.d.ts +14 -0
- package/dist/TextInput/TextInput.spec.d.ts +1 -0
- package/dist/TextInput/TextInput.test.d.ts +1 -0
- package/dist/Toggle/Toggle.d.ts +14 -0
- package/dist/Toggle/Toggle.spec.d.ts +1 -0
- package/dist/Toggle/Toggle.test.d.ts +1 -0
- package/dist/index.css +2 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +700 -0
- package/package.json +17 -3
- package/src/Box/Box.md +0 -41
- package/src/Box/Box.spec.ts +0 -13
- package/src/Box/Box.test.ts +0 -49
- package/src/Box/Box.vue +0 -52
- package/src/Button/Button.md +0 -55
- package/src/Button/Button.spec.ts +0 -18
- package/src/Button/Button.test.ts +0 -36
- package/src/Button/Button.vue +0 -81
- package/src/Expander/Expander.md +0 -23
- package/src/Expander/Expander.spec.ts +0 -14
- package/src/Expander/Expander.vue +0 -95
- package/src/Hint/Hint.md +0 -24
- package/src/Hint/Hint.spec.ts +0 -12
- package/src/Hint/Hint.test.ts +0 -34
- package/src/Hint/Hint.vue +0 -83
- package/src/Icon/Icon.md +0 -55
- package/src/Icon/Icon.spec.ts +0 -9
- package/src/Icon/Icon.vue +0 -112
- package/src/LightDarkToggle/LightDarkToggle.vue +0 -49
- package/src/NumberInput/NumberInput.md +0 -187
- package/src/NumberInput/NumberInput.spec.ts +0 -10
- package/src/NumberInput/NumberInput.test.ts +0 -580
- package/src/NumberInput/NumberInput.vue +0 -446
- package/src/SelectBox/SelectBox.md +0 -56
- package/src/SelectBox/SelectBox.spec.ts +0 -9
- package/src/SelectBox/SelectBox.test.ts +0 -42
- package/src/SelectBox/SelectBox.vue +0 -190
- package/src/SidebarLayout/SidebarLayout.md +0 -104
- package/src/SidebarLayout/SidebarLayout.test.ts +0 -86
- package/src/SidebarLayout/SidebarLayout.vue +0 -465
- package/src/Spinner/Spinner.md +0 -45
- package/src/Spinner/Spinner.spec.ts +0 -9
- package/src/Spinner/Spinner.vue +0 -55
- package/src/TextInput/TextInput.md +0 -41
- package/src/TextInput/TextInput.spec.ts +0 -10
- package/src/TextInput/TextInput.test.ts +0 -70
- package/src/TextInput/TextInput.vue +0 -90
- package/src/Toggle/Toggle.md +0 -68
- package/src/Toggle/Toggle.spec.ts +0 -13
- package/src/Toggle/Toggle.test.ts +0 -35
- package/src/Toggle/Toggle.vue +0 -81
- package/src/index.ts +0 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cfasim-ui/components",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vue 3 UI components for cfasim-ui",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -13,11 +13,21 @@
|
|
|
13
13
|
"access": "public"
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
|
-
"
|
|
16
|
+
"dist"
|
|
17
17
|
],
|
|
18
|
+
"main": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
18
20
|
"exports": {
|
|
19
|
-
".":
|
|
21
|
+
".": {
|
|
22
|
+
"development": "./src/index.ts",
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"import": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./style.css": "./dist/style.css"
|
|
20
27
|
},
|
|
28
|
+
"sideEffects": [
|
|
29
|
+
"*.css"
|
|
30
|
+
],
|
|
21
31
|
"dependencies": {
|
|
22
32
|
"reka-ui": "^2.9.2"
|
|
23
33
|
},
|
|
@@ -26,8 +36,12 @@
|
|
|
26
36
|
},
|
|
27
37
|
"devDependencies": {
|
|
28
38
|
"@vitejs/plugin-vue": "^6.0.5",
|
|
39
|
+
"vite-plugin-dts": "^4.5.4",
|
|
29
40
|
"@vue/test-utils": "^2.4.6",
|
|
30
41
|
"happy-dom": "^20.8.9",
|
|
31
42
|
"vitest": "^4.1.0"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "vite build"
|
|
32
46
|
}
|
|
33
47
|
}
|
package/src/Box/Box.md
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Box
|
|
2
|
-
|
|
3
|
-
A colored container for callouts, alerts, and grouped content.
|
|
4
|
-
|
|
5
|
-
## Examples
|
|
6
|
-
|
|
7
|
-
### Variants
|
|
8
|
-
|
|
9
|
-
<ComponentDemo>
|
|
10
|
-
<Box variant="info">This is an info box.</Box>
|
|
11
|
-
<Box variant="success">This is a success box.</Box>
|
|
12
|
-
<Box variant="warning">This is a warning box.</Box>
|
|
13
|
-
<Box variant="error">This is an error box.</Box>
|
|
14
|
-
|
|
15
|
-
<template #code>
|
|
16
|
-
|
|
17
|
-
```vue
|
|
18
|
-
<Box variant="info">This is an info box.</Box>
|
|
19
|
-
<Box variant="success">This is a success box.</Box>
|
|
20
|
-
<Box variant="warning">This is a warning box.</Box>
|
|
21
|
-
<Box variant="error">This is an error box.</Box>
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
</template>
|
|
25
|
-
</ComponentDemo>
|
|
26
|
-
|
|
27
|
-
### Custom colors
|
|
28
|
-
|
|
29
|
-
<ComponentDemo>
|
|
30
|
-
<Box bg-color="#f0e6ff" text-color="#4a1d96">Custom purple box</Box>
|
|
31
|
-
|
|
32
|
-
<template #code>
|
|
33
|
-
|
|
34
|
-
```vue
|
|
35
|
-
<Box bg-color="#f0e6ff" text-color="#4a1d96">Custom purple box</Box>
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
</template>
|
|
39
|
-
</ComponentDemo>
|
|
40
|
-
|
|
41
|
-
<!--@include: ./_api/box.md-->
|
package/src/Box/Box.spec.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { test, expect } from "@playwright/test";
|
|
2
|
-
|
|
3
|
-
test("Box page renders demos", async ({ page }) => {
|
|
4
|
-
await page.goto("./cfasim-ui/components/box");
|
|
5
|
-
await expect(page.locator("h1")).toBeVisible();
|
|
6
|
-
const demos = page.locator(".demo-preview");
|
|
7
|
-
await expect(demos.first()).toBeVisible();
|
|
8
|
-
await expect(demos.first().locator(".box")).toHaveCount(4);
|
|
9
|
-
await expect(demos.first().getByText("This is an info box.")).toBeVisible();
|
|
10
|
-
await expect(demos.first().getByText("This is a success box.")).toBeVisible();
|
|
11
|
-
await expect(demos.first().getByText("This is a warning box.")).toBeVisible();
|
|
12
|
-
await expect(demos.first().getByText("This is an error box.")).toBeVisible();
|
|
13
|
-
});
|
package/src/Box/Box.test.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { mount } from "@vue/test-utils";
|
|
3
|
-
import Box from "./Box.vue";
|
|
4
|
-
|
|
5
|
-
describe("Box", () => {
|
|
6
|
-
it("renders slot content", () => {
|
|
7
|
-
const wrapper = mount(Box, {
|
|
8
|
-
props: { variant: "info" },
|
|
9
|
-
slots: { default: "Hello" },
|
|
10
|
-
});
|
|
11
|
-
expect(wrapper.text()).toBe("Hello");
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it.each(["info", "success", "warning", "error"] as const)(
|
|
15
|
-
"applies %s variant class",
|
|
16
|
-
(variant) => {
|
|
17
|
-
const wrapper = mount(Box, {
|
|
18
|
-
props: { variant },
|
|
19
|
-
slots: { default: "Content" },
|
|
20
|
-
});
|
|
21
|
-
expect(wrapper.classes()).toContain(`box-${variant}`);
|
|
22
|
-
},
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
it("applies custom role", () => {
|
|
26
|
-
const wrapper = mount(Box, {
|
|
27
|
-
props: { variant: "warning", role: "alert" },
|
|
28
|
-
slots: { default: "Warning" },
|
|
29
|
-
});
|
|
30
|
-
expect(wrapper.attributes("role")).toBe("alert");
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it("has no role by default", () => {
|
|
34
|
-
const wrapper = mount(Box, {
|
|
35
|
-
slots: { default: "Content" },
|
|
36
|
-
});
|
|
37
|
-
expect(wrapper.attributes("role")).toBeUndefined();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it("applies custom bgColor and textColor", () => {
|
|
41
|
-
const wrapper = mount(Box, {
|
|
42
|
-
props: { bgColor: "#fef3e6", textColor: "#7a3d00" },
|
|
43
|
-
slots: { default: "Custom" },
|
|
44
|
-
});
|
|
45
|
-
const style = wrapper.attributes("style") ?? "";
|
|
46
|
-
expect(style).toContain("background-color");
|
|
47
|
-
expect(style).toContain("color");
|
|
48
|
-
});
|
|
49
|
-
});
|
package/src/Box/Box.vue
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
export type BoxVariant = "info" | "success" | "warning" | "error";
|
|
3
|
-
|
|
4
|
-
defineProps<{
|
|
5
|
-
variant?: BoxVariant;
|
|
6
|
-
bgColor?: string;
|
|
7
|
-
textColor?: string;
|
|
8
|
-
role?: string;
|
|
9
|
-
}>();
|
|
10
|
-
</script>
|
|
11
|
-
|
|
12
|
-
<template>
|
|
13
|
-
<div
|
|
14
|
-
class="box"
|
|
15
|
-
:class="variant ? `box-${variant}` : undefined"
|
|
16
|
-
:style="{
|
|
17
|
-
backgroundColor: bgColor,
|
|
18
|
-
color: textColor,
|
|
19
|
-
}"
|
|
20
|
-
:role="role"
|
|
21
|
-
>
|
|
22
|
-
<slot />
|
|
23
|
-
</div>
|
|
24
|
-
</template>
|
|
25
|
-
|
|
26
|
-
<style scoped>
|
|
27
|
-
.box {
|
|
28
|
-
padding: 0.75em 1.25em;
|
|
29
|
-
border-radius: 0.375em;
|
|
30
|
-
font-size: var(--font-size-sm);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.box-info {
|
|
34
|
-
background-color: var(--color-box-info-bg);
|
|
35
|
-
color: var(--color-box-info-text);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.box-success {
|
|
39
|
-
background-color: var(--color-box-success-bg);
|
|
40
|
-
color: var(--color-box-success-text);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.box-warning {
|
|
44
|
-
background-color: var(--color-box-warning-bg);
|
|
45
|
-
color: var(--color-box-warning-text);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
.box-error {
|
|
49
|
-
background-color: var(--color-box-error-bg);
|
|
50
|
-
color: var(--color-box-error-text);
|
|
51
|
-
}
|
|
52
|
-
</style>
|
package/src/Button/Button.md
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# Button
|
|
2
|
-
|
|
3
|
-
A button for triggering actions. Supports primary and secondary variants.
|
|
4
|
-
|
|
5
|
-
Built on [reka-ui Primitive](https://reka-ui.com/docs/utilities/primitive), so it supports `as` and `asChild` for rendering as different elements.
|
|
6
|
-
|
|
7
|
-
## Examples
|
|
8
|
-
|
|
9
|
-
### Variants
|
|
10
|
-
|
|
11
|
-
<ComponentDemo>
|
|
12
|
-
<Button>Primary</Button>
|
|
13
|
-
<Button variant="secondary">Secondary</Button>
|
|
14
|
-
|
|
15
|
-
<template #code>
|
|
16
|
-
|
|
17
|
-
```vue
|
|
18
|
-
<Button>Primary</Button>
|
|
19
|
-
<Button variant="secondary">Secondary</Button>
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
</template>
|
|
23
|
-
</ComponentDemo>
|
|
24
|
-
|
|
25
|
-
### Disabled
|
|
26
|
-
|
|
27
|
-
<ComponentDemo>
|
|
28
|
-
<Button disabled>Disabled</Button>
|
|
29
|
-
<Button variant="secondary" disabled>Disabled</Button>
|
|
30
|
-
|
|
31
|
-
<template #code>
|
|
32
|
-
|
|
33
|
-
```vue
|
|
34
|
-
<Button disabled>Disabled</Button>
|
|
35
|
-
<Button variant="secondary" disabled>Disabled</Button>
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
</template>
|
|
39
|
-
</ComponentDemo>
|
|
40
|
-
|
|
41
|
-
### With label prop
|
|
42
|
-
|
|
43
|
-
<ComponentDemo>
|
|
44
|
-
<Button label="Click me" />
|
|
45
|
-
|
|
46
|
-
<template #code>
|
|
47
|
-
|
|
48
|
-
```vue
|
|
49
|
-
<Button label="Click me" />
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
</template>
|
|
53
|
-
</ComponentDemo>
|
|
54
|
-
|
|
55
|
-
<!--@include: ./_api/button.md-->
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { test, expect } from "@playwright/test";
|
|
2
|
-
|
|
3
|
-
test("Button page renders demos", async ({ page }) => {
|
|
4
|
-
await page.goto("./cfasim-ui/components/button");
|
|
5
|
-
await expect(page.locator("h1")).toBeVisible();
|
|
6
|
-
const demos = page.locator(".demo-preview");
|
|
7
|
-
await expect(demos.first()).toBeVisible();
|
|
8
|
-
await expect(
|
|
9
|
-
demos.first().getByRole("button", { name: "Primary" }),
|
|
10
|
-
).toBeVisible();
|
|
11
|
-
await expect(
|
|
12
|
-
demos.first().getByRole("button", { name: "Secondary" }),
|
|
13
|
-
).toBeVisible();
|
|
14
|
-
|
|
15
|
-
// Disabled demo
|
|
16
|
-
const disabledDemo = demos.nth(1);
|
|
17
|
-
await expect(disabledDemo.getByRole("button").first()).toBeDisabled();
|
|
18
|
-
});
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { mount } from "@vue/test-utils";
|
|
3
|
-
import Button from "./Button.vue";
|
|
4
|
-
|
|
5
|
-
describe("Button", () => {
|
|
6
|
-
it("renders with default slot content", () => {
|
|
7
|
-
const wrapper = mount(Button, {
|
|
8
|
-
slots: { default: "Click me" },
|
|
9
|
-
});
|
|
10
|
-
expect(wrapper.text()).toBe("Click me");
|
|
11
|
-
expect(wrapper.element.tagName).toBe("BUTTON");
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it("renders with label prop", () => {
|
|
15
|
-
const wrapper = mount(Button, {
|
|
16
|
-
props: { label: "Submit" },
|
|
17
|
-
});
|
|
18
|
-
expect(wrapper.text()).toBe("Submit");
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it("emits click event", async () => {
|
|
22
|
-
const wrapper = mount(Button, {
|
|
23
|
-
slots: { default: "Click me" },
|
|
24
|
-
});
|
|
25
|
-
await wrapper.trigger("click");
|
|
26
|
-
expect(wrapper.emitted("click")).toHaveLength(1);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it("renders as different element via as prop", () => {
|
|
30
|
-
const wrapper = mount(Button, {
|
|
31
|
-
props: { as: "a" },
|
|
32
|
-
slots: { default: "Link" },
|
|
33
|
-
});
|
|
34
|
-
expect(wrapper.element.tagName).toBe("A");
|
|
35
|
-
});
|
|
36
|
-
});
|
package/src/Button/Button.vue
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { Primitive } from "reka-ui";
|
|
3
|
-
import type { PrimitiveProps } from "reka-ui";
|
|
4
|
-
|
|
5
|
-
interface Props extends PrimitiveProps {
|
|
6
|
-
label?: string;
|
|
7
|
-
variant?: "primary" | "secondary";
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
withDefaults(defineProps<Props>(), {
|
|
11
|
-
as: "button",
|
|
12
|
-
variant: "primary",
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
defineEmits<{
|
|
16
|
-
click: [event: MouseEvent];
|
|
17
|
-
}>();
|
|
18
|
-
</script>
|
|
19
|
-
|
|
20
|
-
<template>
|
|
21
|
-
<Primitive
|
|
22
|
-
class="button"
|
|
23
|
-
:data-variant="variant"
|
|
24
|
-
:as="as"
|
|
25
|
-
:as-child="asChild"
|
|
26
|
-
@click="$emit('click', $event)"
|
|
27
|
-
>
|
|
28
|
-
<slot>{{ label }}</slot>
|
|
29
|
-
</Primitive>
|
|
30
|
-
</template>
|
|
31
|
-
|
|
32
|
-
<style scoped>
|
|
33
|
-
.button {
|
|
34
|
-
display: inline-flex;
|
|
35
|
-
border: none;
|
|
36
|
-
align-items: center;
|
|
37
|
-
justify-content: center;
|
|
38
|
-
align-self: flex-start;
|
|
39
|
-
flex-shrink: 0;
|
|
40
|
-
min-height: 2.5em;
|
|
41
|
-
padding: 0 1em;
|
|
42
|
-
font-size: var(--font-size-sm);
|
|
43
|
-
font-weight: 500;
|
|
44
|
-
border-radius: 0.375em;
|
|
45
|
-
background-color: var(--color-primary);
|
|
46
|
-
color: var(--color-text-on-primary);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.button:hover {
|
|
50
|
-
cursor: pointer;
|
|
51
|
-
background-color: var(--color-primary-hover);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.button:active {
|
|
55
|
-
background-color: var(--color-primary-active);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.button:focus-visible {
|
|
59
|
-
outline: none;
|
|
60
|
-
box-shadow: var(--shadow-focus);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.button:disabled {
|
|
64
|
-
opacity: 0.5;
|
|
65
|
-
cursor: not-allowed;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.button[data-variant="secondary"] {
|
|
69
|
-
background-color: transparent;
|
|
70
|
-
color: var(--color-primary);
|
|
71
|
-
border: 1px solid var(--color-primary);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.button[data-variant="secondary"]:hover {
|
|
75
|
-
background-color: color-mix(in srgb, var(--color-primary) 10%, transparent);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.button[data-variant="secondary"]:active {
|
|
79
|
-
background-color: color-mix(in srgb, var(--color-primary) 15%, transparent);
|
|
80
|
-
}
|
|
81
|
-
</style>
|
package/src/Expander/Expander.md
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# Expander
|
|
2
|
-
|
|
3
|
-
A collapsible section that toggles content visibility.
|
|
4
|
-
|
|
5
|
-
## Examples
|
|
6
|
-
|
|
7
|
-
<ComponentDemo>
|
|
8
|
-
<Expander label="Show advanced options">
|
|
9
|
-
<p style="margin: 0">Here is the hidden content.</p>
|
|
10
|
-
</Expander>
|
|
11
|
-
|
|
12
|
-
<template #code>
|
|
13
|
-
|
|
14
|
-
```vue
|
|
15
|
-
<Expander label="Show advanced options">
|
|
16
|
-
<p>Here is the hidden content.</p>
|
|
17
|
-
</Expander>
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
</template>
|
|
21
|
-
</ComponentDemo>
|
|
22
|
-
|
|
23
|
-
<!--@include: ./_api/expander.md-->
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { test, expect } from "@playwright/test";
|
|
2
|
-
|
|
3
|
-
test("Expander page renders demos", async ({ page }) => {
|
|
4
|
-
await page.goto("./cfasim-ui/components/expander");
|
|
5
|
-
await expect(page.locator("h1")).toBeVisible();
|
|
6
|
-
const demos = page.locator(".demo-preview");
|
|
7
|
-
await expect(demos.first()).toBeVisible();
|
|
8
|
-
const trigger = demos.first().getByText("Show advanced options");
|
|
9
|
-
await expect(trigger).toBeVisible();
|
|
10
|
-
await trigger.click();
|
|
11
|
-
await expect(
|
|
12
|
-
demos.first().getByText("Here is the hidden content."),
|
|
13
|
-
).toBeVisible();
|
|
14
|
-
});
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
CollapsibleRoot,
|
|
4
|
-
CollapsibleTrigger,
|
|
5
|
-
CollapsibleContent,
|
|
6
|
-
} from "reka-ui";
|
|
7
|
-
|
|
8
|
-
const open = defineModel<boolean>("open", { default: false });
|
|
9
|
-
|
|
10
|
-
defineProps<{
|
|
11
|
-
label?: string;
|
|
12
|
-
}>();
|
|
13
|
-
</script>
|
|
14
|
-
|
|
15
|
-
<template>
|
|
16
|
-
<CollapsibleRoot v-model:open="open" class="expander">
|
|
17
|
-
<CollapsibleTrigger class="expander-trigger">
|
|
18
|
-
<span class="expander-caret" :class="{ open }" />
|
|
19
|
-
<slot name="label">{{ label }}</slot>
|
|
20
|
-
</CollapsibleTrigger>
|
|
21
|
-
<CollapsibleContent class="expander-content">
|
|
22
|
-
<slot />
|
|
23
|
-
</CollapsibleContent>
|
|
24
|
-
</CollapsibleRoot>
|
|
25
|
-
</template>
|
|
26
|
-
|
|
27
|
-
<style scoped>
|
|
28
|
-
.expander-trigger {
|
|
29
|
-
display: flex;
|
|
30
|
-
align-items: center;
|
|
31
|
-
gap: 0.5em;
|
|
32
|
-
width: 100%;
|
|
33
|
-
padding: 0.5em 0;
|
|
34
|
-
background: none;
|
|
35
|
-
border: none;
|
|
36
|
-
cursor: pointer;
|
|
37
|
-
font: inherit;
|
|
38
|
-
font-size: var(--font-size-sm);
|
|
39
|
-
font-weight: 600;
|
|
40
|
-
text-transform: uppercase;
|
|
41
|
-
letter-spacing: 0.05em;
|
|
42
|
-
color: var(--color-text-secondary);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.expander-trigger:hover {
|
|
46
|
-
color: var(--color-text);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.expander-caret {
|
|
50
|
-
display: inline-block;
|
|
51
|
-
width: 0;
|
|
52
|
-
height: 0;
|
|
53
|
-
border-left: 0.35em solid currentColor;
|
|
54
|
-
border-top: 0.3em solid transparent;
|
|
55
|
-
border-bottom: 0.3em solid transparent;
|
|
56
|
-
transition: transform 0.15s;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.expander-caret.open {
|
|
60
|
-
transform: rotate(90deg);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.expander-content {
|
|
64
|
-
overflow: hidden;
|
|
65
|
-
display: flex;
|
|
66
|
-
flex-direction: column;
|
|
67
|
-
gap: 0.75em;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.expander-content[data-state="open"] {
|
|
71
|
-
animation: slideDown 200ms ease-out;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.expander-content[data-state="closed"] {
|
|
75
|
-
animation: slideUp 200ms ease-out;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
@keyframes slideDown {
|
|
79
|
-
from {
|
|
80
|
-
height: 0;
|
|
81
|
-
}
|
|
82
|
-
to {
|
|
83
|
-
height: var(--reka-collapsible-content-height);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
@keyframes slideUp {
|
|
88
|
-
from {
|
|
89
|
-
height: var(--reka-collapsible-content-height);
|
|
90
|
-
}
|
|
91
|
-
to {
|
|
92
|
-
height: 0;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
</style>
|
package/src/Hint/Hint.md
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Hint
|
|
2
|
-
|
|
3
|
-
An info icon that shows a tooltip on hover. Used alongside form labels to provide additional context.
|
|
4
|
-
|
|
5
|
-
## Examples
|
|
6
|
-
|
|
7
|
-
<ComponentDemo>
|
|
8
|
-
<span style="display: flex; align-items: center; gap: 8px;">
|
|
9
|
-
Population size <Hint text="The total number of individuals in the simulation." />
|
|
10
|
-
</span>
|
|
11
|
-
|
|
12
|
-
<template #code>
|
|
13
|
-
|
|
14
|
-
```vue
|
|
15
|
-
<span style="display: flex; align-items: center; gap: 8px;">
|
|
16
|
-
Population size
|
|
17
|
-
<Hint text="The total number of individuals in the simulation." />
|
|
18
|
-
</span>
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
</template>
|
|
22
|
-
</ComponentDemo>
|
|
23
|
-
|
|
24
|
-
<!--@include: ./_api/hint.md-->
|
package/src/Hint/Hint.spec.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { test, expect } from "@playwright/test";
|
|
2
|
-
|
|
3
|
-
test("Hint page renders demos", async ({ page }) => {
|
|
4
|
-
await page.goto("./cfasim-ui/components/hint");
|
|
5
|
-
await expect(page.locator("h1")).toBeVisible();
|
|
6
|
-
const demos = page.locator(".demo-preview");
|
|
7
|
-
await expect(demos.first()).toBeVisible();
|
|
8
|
-
await expect(demos.first().getByText("Population size")).toBeVisible();
|
|
9
|
-
await expect(
|
|
10
|
-
demos.first().getByRole("button", { name: "More info" }),
|
|
11
|
-
).toBeVisible();
|
|
12
|
-
});
|
package/src/Hint/Hint.test.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { mount } from "@vue/test-utils";
|
|
3
|
-
import Hint from "./Hint.vue";
|
|
4
|
-
|
|
5
|
-
describe("Hint", () => {
|
|
6
|
-
it("renders a trigger button with help icon", () => {
|
|
7
|
-
const wrapper = mount(Hint, {
|
|
8
|
-
props: { text: "Some hint text" },
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
const button = wrapper.find(".HintTrigger");
|
|
12
|
-
expect(button.exists()).toBe(true);
|
|
13
|
-
expect(button.attributes("aria-label")).toBe("More info");
|
|
14
|
-
expect(button.attributes("type")).toBe("button");
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it("renders the help icon inside the trigger", () => {
|
|
18
|
-
const wrapper = mount(Hint, {
|
|
19
|
-
props: { text: "Some hint text" },
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const icon = wrapper.find(".HintTrigger .Icon");
|
|
23
|
-
expect(icon.exists()).toBe(true);
|
|
24
|
-
expect(icon.text()).toBe("help");
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it("does not show tooltip content by default", () => {
|
|
28
|
-
const wrapper = mount(Hint, {
|
|
29
|
-
props: { text: "Hidden until hover" },
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
expect(wrapper.text()).not.toContain("Hidden until hover");
|
|
33
|
-
});
|
|
34
|
-
});
|
package/src/Hint/Hint.vue
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
TooltipArrow,
|
|
4
|
-
TooltipContent,
|
|
5
|
-
TooltipPortal,
|
|
6
|
-
TooltipProvider,
|
|
7
|
-
TooltipRoot,
|
|
8
|
-
TooltipTrigger,
|
|
9
|
-
} from "reka-ui";
|
|
10
|
-
import Icon from "../Icon/Icon.vue";
|
|
11
|
-
|
|
12
|
-
defineProps<{
|
|
13
|
-
text: string;
|
|
14
|
-
}>();
|
|
15
|
-
</script>
|
|
16
|
-
|
|
17
|
-
<template>
|
|
18
|
-
<TooltipProvider>
|
|
19
|
-
<TooltipRoot :delay-duration="0" disable-closing-trigger>
|
|
20
|
-
<TooltipTrigger as-child>
|
|
21
|
-
<button
|
|
22
|
-
type="button"
|
|
23
|
-
class="HintTrigger"
|
|
24
|
-
aria-label="More info"
|
|
25
|
-
@pointerdown.prevent
|
|
26
|
-
>
|
|
27
|
-
<Icon icon="help" :size="16" />
|
|
28
|
-
</button>
|
|
29
|
-
</TooltipTrigger>
|
|
30
|
-
<TooltipPortal>
|
|
31
|
-
<TooltipContent class="HintContent" side="top" :side-offset="4">
|
|
32
|
-
{{ text }}
|
|
33
|
-
<TooltipArrow class="HintArrow" :width="10" :height="5" />
|
|
34
|
-
</TooltipContent>
|
|
35
|
-
</TooltipPortal>
|
|
36
|
-
</TooltipRoot>
|
|
37
|
-
</TooltipProvider>
|
|
38
|
-
</template>
|
|
39
|
-
|
|
40
|
-
<style scoped>
|
|
41
|
-
.HintTrigger {
|
|
42
|
-
display: inline-flex;
|
|
43
|
-
align-items: center;
|
|
44
|
-
justify-content: center;
|
|
45
|
-
width: 1.25em;
|
|
46
|
-
height: 1.25em;
|
|
47
|
-
padding: 0;
|
|
48
|
-
margin: 0;
|
|
49
|
-
border: none;
|
|
50
|
-
border-radius: 50%;
|
|
51
|
-
background: transparent;
|
|
52
|
-
color: var(--color-text-secondary);
|
|
53
|
-
cursor: pointer;
|
|
54
|
-
flex-shrink: 0;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.HintTrigger:hover {
|
|
58
|
-
color: var(--color-text);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.HintTrigger:focus-visible {
|
|
62
|
-
outline: none;
|
|
63
|
-
box-shadow: var(--shadow-focus);
|
|
64
|
-
}
|
|
65
|
-
</style>
|
|
66
|
-
|
|
67
|
-
<style>
|
|
68
|
-
.HintContent {
|
|
69
|
-
max-width: 15rem;
|
|
70
|
-
padding: 0.5em 0.75em;
|
|
71
|
-
font-size: var(--font-size-xs);
|
|
72
|
-
line-height: 1.4;
|
|
73
|
-
color: var(--color-bg-0);
|
|
74
|
-
background-color: var(--color-text);
|
|
75
|
-
border-radius: 0.25em;
|
|
76
|
-
box-shadow: var(--shadow-md);
|
|
77
|
-
z-index: 100;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.HintArrow {
|
|
81
|
-
fill: var(--color-text);
|
|
82
|
-
}
|
|
83
|
-
</style>
|