@aggc/ui 0.4.1 → 0.5.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.
Files changed (88) hide show
  1. package/README.md +19 -0
  2. package/package.json +4 -2
  3. package/src/components/PageSurface.styles.ts +3 -0
  4. package/src/components/PageSurface.vue +9 -0
  5. package/src/components/ResultPanel.styles.ts +108 -0
  6. package/src/components/ResultPanel.test.ts +22 -0
  7. package/src/components/ResultPanel.vue +70 -0
  8. package/src/components/SectionCard.styles.ts +65 -0
  9. package/src/components/SectionCard.test.ts +22 -0
  10. package/src/components/SectionCard.vue +51 -0
  11. package/src/components/StatusBadge.styles.ts +49 -0
  12. package/src/components/StatusBadge.test.ts +18 -0
  13. package/src/components/StatusBadge.vue +18 -0
  14. package/src/components/UiButton.styles.ts +29 -0
  15. package/src/components/UiButton.test.ts +21 -0
  16. package/src/components/UiButton.vue +46 -0
  17. package/src/components/UiCheckbox.styles.ts +118 -0
  18. package/src/components/UiCheckbox.test.ts +18 -0
  19. package/src/components/UiCheckbox.vue +72 -0
  20. package/src/components/UiField.styles.ts +35 -0
  21. package/src/components/UiField.test.ts +22 -0
  22. package/src/components/UiField.vue +36 -0
  23. package/src/components/UiLoadingState.styles.ts +36 -0
  24. package/src/components/UiLoadingState.vue +34 -0
  25. package/src/components/UiSegmentedControl.styles.ts +49 -0
  26. package/src/components/UiSegmentedControl.vue +30 -0
  27. package/src/components/UiSelect.styles.ts +214 -0
  28. package/src/components/UiSelect.test.ts +49 -0
  29. package/src/components/UiSelect.vue +256 -0
  30. package/src/components/UiSkeleton.styles.ts +93 -0
  31. package/src/components/UiSkeleton.vue +48 -0
  32. package/src/components/index.ts +11 -0
  33. package/src/components.ts +1 -0
  34. package/src/css/base.css +62 -0
  35. package/src/css/fonts.css +6 -0
  36. package/src/css/index.css +2 -0
  37. package/src/css/storybook.css +15 -0
  38. package/src/env.d.ts +1 -0
  39. package/src/index.ts +3 -0
  40. package/src/stories/feedback/ResultPanel.stories.ts +76 -0
  41. package/src/stories/feedback/StatusBadge.stories.ts +50 -0
  42. package/src/stories/feedback/UiLoadingState.stories.ts +52 -0
  43. package/src/stories/feedback/UiSkeleton.stories.ts +85 -0
  44. package/src/stories/forms/UiCheckbox.stories.ts +104 -0
  45. package/src/stories/forms/UiField.stories.ts +87 -0
  46. package/src/stories/forms/UiSelect.stories.ts +134 -0
  47. package/src/stories/layout/PageSurface.stories.ts +53 -0
  48. package/src/stories/layout/SectionCard.stories.ts +85 -0
  49. package/src/stories/primitives/UiButton.stories.ts +145 -0
  50. package/src/stories/primitives/UiSegmentedControl.stories.ts +67 -0
  51. package/src/stories/support/StoryThemeFrame.vue +101 -0
  52. package/src/stories/support/sources.ts +374 -0
  53. package/src/stories/support/storyStyles.ts +150 -0
  54. package/src/styles/README.md +23 -0
  55. package/src/styles/index.ts +20 -0
  56. package/src/styles/layouts/cluster.ts +27 -0
  57. package/src/styles/layouts/page.ts +22 -0
  58. package/src/styles/layouts/split.ts +26 -0
  59. package/src/styles/layouts/stack.ts +21 -0
  60. package/src/styles/patterns/actionToolbar.ts +8 -0
  61. package/src/styles/patterns/emptyState.ts +23 -0
  62. package/src/styles/patterns/infoPanel.ts +22 -0
  63. package/src/styles/patterns/metricGrid.ts +19 -0
  64. package/src/styles/patterns/pageHeader.ts +19 -0
  65. package/src/styles/patterns/resultRegion.ts +7 -0
  66. package/src/styles/patterns/selectableListDetail.ts +21 -0
  67. package/src/styles/primitives/feedback.ts +23 -0
  68. package/src/styles/primitives/fields.ts +76 -0
  69. package/src/styles/primitives/surfaces.ts +52 -0
  70. package/src/styles/primitives/typography.ts +42 -0
  71. package/src/styles/recipes/badge.recipe.ts +54 -0
  72. package/src/styles/recipes/button.recipe.ts +115 -0
  73. package/src/styles/recipes/card.recipe.ts +64 -0
  74. package/src/styles/recipes/dropdown.recipe.ts +40 -0
  75. package/src/styles/recipes/input.recipe.ts +59 -0
  76. package/src/styles.ts +1 -0
  77. package/src/test/setup.ts +1 -0
  78. package/src/tokens/colors.ts +16 -0
  79. package/src/tokens/core-colors.ts +53 -0
  80. package/src/tokens/desktop-colors.ts +37 -0
  81. package/src/tokens/index.ts +8 -0
  82. package/src/tokens/motion.ts +6 -0
  83. package/src/tokens/radius.ts +3 -0
  84. package/src/tokens/spacing.ts +4 -0
  85. package/src/tokens/typography.ts +6 -0
  86. package/src/tokens-core.ts +5 -0
  87. package/src/tokens-desktop.ts +1 -0
  88. package/src/tokens.ts +1 -0
@@ -0,0 +1,118 @@
1
+ import { cva, css } from "@styled/css";
2
+
3
+ export const uiCheckboxRootClass = cva({
4
+ base: {
5
+ width: "100%",
6
+ display: "flex",
7
+ alignItems: "flex-start",
8
+ gap: "3",
9
+ textAlign: "left",
10
+ borderRadius: "2xl",
11
+ borderWidth: "1px",
12
+ px: "4",
13
+ py: "3.5",
14
+ color: "text.primary",
15
+ transition: "all 160ms ease",
16
+ },
17
+ variants: {
18
+ checked: {
19
+ true: {
20
+ borderColor: "border.accent",
21
+ bg: "bg.selected",
22
+ boxShadow: "0 18px 40px -30px rgba(49,94,255,0.56)",
23
+ },
24
+ false: {
25
+ borderColor: "border.default",
26
+ bg: "bg.input",
27
+ boxShadow: "0 14px 32px -30px rgba(15,23,42,0.42)",
28
+ },
29
+ },
30
+ disabled: {
31
+ true: {
32
+ cursor: "not-allowed",
33
+ opacity: 0.5,
34
+ },
35
+ false: {
36
+ cursor: "pointer",
37
+ },
38
+ },
39
+ },
40
+ compoundVariants: [
41
+ {
42
+ checked: true,
43
+ disabled: false,
44
+ css: {
45
+ _hover: {
46
+ borderColor: "border.accent",
47
+ transform: "translateY(-1px)",
48
+ },
49
+ },
50
+ },
51
+ {
52
+ checked: false,
53
+ disabled: false,
54
+ css: {
55
+ _hover: {
56
+ borderColor: "border.strong",
57
+ transform: "translateY(-1px)",
58
+ },
59
+ },
60
+ },
61
+ ],
62
+ defaultVariants: {
63
+ checked: false,
64
+ disabled: false,
65
+ },
66
+ });
67
+
68
+ export const uiCheckboxIndicatorClass = cva({
69
+ base: {
70
+ mt: "0.5",
71
+ flexShrink: "0",
72
+ width: "22px",
73
+ height: "22px",
74
+ borderRadius: "md",
75
+ borderWidth: "1px",
76
+ display: "flex",
77
+ alignItems: "center",
78
+ justifyContent: "center",
79
+ transition: "all 160ms ease",
80
+ },
81
+ variants: {
82
+ checked: {
83
+ true: {
84
+ borderColor: "border.accent",
85
+ bg: "bg.accentStrong",
86
+ color: "text.inverse",
87
+ boxShadow: "0 12px 24px -16px rgba(49,94,255,0.7)",
88
+ },
89
+ false: {
90
+ borderColor: "border.default",
91
+ bg: "bg.buttonOutline",
92
+ color: "transparent",
93
+ boxShadow: "inset 0 1px 0 rgba(255,255,255,0.32)",
94
+ },
95
+ },
96
+ },
97
+ defaultVariants: {
98
+ checked: false,
99
+ },
100
+ });
101
+
102
+ export const uiCheckboxContentClass = css({
103
+ display: "grid",
104
+ gap: "1",
105
+ minWidth: "0",
106
+ });
107
+
108
+ export const uiCheckboxLabelClass = css({
109
+ fontSize: "sm",
110
+ fontWeight: "700",
111
+ lineHeight: "1.45",
112
+ });
113
+
114
+ export const uiCheckboxDescriptionClass = css({
115
+ color: "text.secondary",
116
+ fontSize: "sm",
117
+ lineHeight: "1.55",
118
+ });
@@ -0,0 +1,18 @@
1
+ import { mount } from "@vue/test-utils";
2
+ import { describe, expect, it } from "vitest";
3
+ import UiCheckbox from "./UiCheckbox.vue";
4
+
5
+ describe("UiCheckbox", () => {
6
+ it("toggles via keyboard", async () => {
7
+ const wrapper = mount(UiCheckbox, {
8
+ props: {
9
+ modelValue: false,
10
+ label: "Enable sync",
11
+ },
12
+ });
13
+
14
+ await wrapper.trigger("keydown.space");
15
+
16
+ expect(wrapper.emitted("update:modelValue")?.[0]).toEqual([true]);
17
+ });
18
+ });
@@ -0,0 +1,72 @@
1
+ <script setup lang="ts">
2
+ import { Check } from "lucide-vue-next";
3
+ import {
4
+ uiCheckboxContentClass,
5
+ uiCheckboxDescriptionClass,
6
+ uiCheckboxIndicatorClass,
7
+ uiCheckboxLabelClass,
8
+ uiCheckboxRootClass,
9
+ } from "./UiCheckbox.styles";
10
+
11
+ const props = withDefaults(
12
+ defineProps<{
13
+ modelValue: boolean;
14
+ id?: string;
15
+ name?: string;
16
+ label?: string;
17
+ description?: string;
18
+ disabled?: boolean;
19
+ invalid?: boolean;
20
+ ariaDescribedby?: string;
21
+ }>(),
22
+ {
23
+ id: undefined,
24
+ name: undefined,
25
+ label: undefined,
26
+ description: undefined,
27
+ disabled: false,
28
+ invalid: false,
29
+ ariaDescribedby: undefined,
30
+ }
31
+ );
32
+
33
+ const emit = defineEmits<{
34
+ "update:modelValue": [boolean];
35
+ }>();
36
+
37
+ function toggle() {
38
+ if (props.disabled) {
39
+ return;
40
+ }
41
+ emit("update:modelValue", !props.modelValue);
42
+ }
43
+ </script>
44
+
45
+ <template>
46
+ <button
47
+ type="button"
48
+ :id="id"
49
+ :name="name"
50
+ role="checkbox"
51
+ :aria-checked="modelValue"
52
+ :aria-describedby="ariaDescribedby"
53
+ :aria-invalid="invalid || undefined"
54
+ :disabled="disabled"
55
+ :class="uiCheckboxRootClass({ checked: modelValue, disabled })"
56
+ @click="toggle"
57
+ @keydown.enter.prevent="toggle"
58
+ @keydown.space.prevent="toggle"
59
+ >
60
+ <span :class="uiCheckboxIndicatorClass({ checked: modelValue })" aria-hidden="true">
61
+ <Check :size="14" />
62
+ </span>
63
+ <span :class="uiCheckboxContentClass">
64
+ <span v-if="label || $slots.default" :class="uiCheckboxLabelClass">
65
+ <slot>{{ label }}</slot>
66
+ </span>
67
+ <span v-if="description || $slots.description" :class="uiCheckboxDescriptionClass">
68
+ <slot name="description">{{ description }}</slot>
69
+ </span>
70
+ </span>
71
+ </button>
72
+ </template>
@@ -0,0 +1,35 @@
1
+ import { css } from "@styled/css";
2
+ import { eyebrowClass, helperTextClass } from "../styles";
3
+
4
+ export const uiFieldRootClass = css({
5
+ display: "grid",
6
+ gap: "2",
7
+ minWidth: "0",
8
+ });
9
+
10
+ export const uiFieldTopRowClass = css({
11
+ display: "flex",
12
+ alignItems: "flex-start",
13
+ justifyContent: "space-between",
14
+ gap: "3",
15
+ });
16
+
17
+ export const uiFieldLabelWrapClass = css({
18
+ display: "grid",
19
+ gap: "1",
20
+ minWidth: "0",
21
+ });
22
+
23
+ export const uiFieldEyebrowClass = eyebrowClass;
24
+
25
+ export const uiFieldLabelClass = css({
26
+ fontSize: "sm",
27
+ fontWeight: "700",
28
+ color: "text.primary",
29
+ });
30
+
31
+ export const uiFieldHintClass = helperTextClass;
32
+
33
+ export const uiFieldMetaClass = css({
34
+ flexShrink: "0",
35
+ });
@@ -0,0 +1,22 @@
1
+ import { mount } from "@vue/test-utils";
2
+ import { describe, expect, it } from "vitest";
3
+ import UiField from "./UiField.vue";
4
+
5
+ describe("UiField", () => {
6
+ it("links label and hint metadata to a control", () => {
7
+ const wrapper = mount(UiField, {
8
+ props: {
9
+ label: "Workspace",
10
+ hint: "Pick the active surface.",
11
+ forId: "workspace",
12
+ id: "workspace-hint",
13
+ },
14
+ slots: {
15
+ default: '<input id="workspace" aria-describedby="workspace-hint" />',
16
+ },
17
+ });
18
+
19
+ expect(wrapper.get("label").attributes("for")).toBe("workspace");
20
+ expect(wrapper.get("#workspace-hint").text()).toContain("Pick the active surface.");
21
+ });
22
+ });
@@ -0,0 +1,36 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ uiFieldEyebrowClass,
4
+ uiFieldHintClass,
5
+ uiFieldLabelClass,
6
+ uiFieldLabelWrapClass,
7
+ uiFieldMetaClass,
8
+ uiFieldRootClass,
9
+ uiFieldTopRowClass,
10
+ } from "./UiField.styles";
11
+
12
+ defineProps<{
13
+ id?: string;
14
+ forId?: string;
15
+ label?: string;
16
+ hint?: string;
17
+ eyebrow?: string;
18
+ }>();
19
+ </script>
20
+
21
+ <template>
22
+ <div :class="uiFieldRootClass">
23
+ <div v-if="eyebrow || label || hint || $slots.meta" :class="uiFieldTopRowClass">
24
+ <div :class="uiFieldLabelWrapClass">
25
+ <p v-if="eyebrow" :class="uiFieldEyebrowClass">{{ eyebrow }}</p>
26
+ <label v-if="label" :for="forId" :class="uiFieldLabelClass">{{ label }}</label>
27
+ <p v-if="hint" :id="id" :class="uiFieldHintClass">{{ hint }}</p>
28
+ </div>
29
+ <div v-if="$slots.meta" :class="uiFieldMetaClass">
30
+ <slot name="meta" />
31
+ </div>
32
+ </div>
33
+
34
+ <slot />
35
+ </div>
36
+ </template>
@@ -0,0 +1,36 @@
1
+ import { css, cx } from "@styled/css";
2
+ import { insetPanelClass } from "../styles";
3
+
4
+ export const uiLoadingStateRootClass = cx(
5
+ insetPanelClass,
6
+ css({
7
+ paddingX: "4",
8
+ paddingY: "3",
9
+ display: "flex",
10
+ alignItems: "center",
11
+ gap: "3",
12
+ color: "text.secondary",
13
+ fontSize: "sm",
14
+ lineHeight: "1.5",
15
+ })
16
+ );
17
+
18
+ export const uiLoadingStatePulseClass = css({
19
+ width: "2.5",
20
+ height: "2.5",
21
+ borderRadius: "full",
22
+ flexShrink: "0",
23
+ bg: "text.accent",
24
+ boxShadow: "0 0 0 0 rgba(49,94,255,0.35)",
25
+ animation: "loadingPulse 1.2s ease-out infinite",
26
+ });
27
+
28
+ export const uiLoadingStateContentClass = css({
29
+ display: "grid",
30
+ gap: "0.5",
31
+ });
32
+
33
+ export const uiLoadingStateTitleClass = css({
34
+ fontWeight: "700",
35
+ color: "text.primary",
36
+ });
@@ -0,0 +1,34 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ uiLoadingStateContentClass,
4
+ uiLoadingStatePulseClass,
5
+ uiLoadingStateRootClass,
6
+ uiLoadingStateTitleClass,
7
+ } from "./UiLoadingState.styles";
8
+
9
+ withDefaults(
10
+ defineProps<{
11
+ title: string;
12
+ description: string;
13
+ live?: "polite" | "assertive" | "off";
14
+ }>(),
15
+ {
16
+ live: "polite",
17
+ }
18
+ );
19
+ </script>
20
+
21
+ <template>
22
+ <div
23
+ :class="uiLoadingStateRootClass"
24
+ data-testid="loading-state"
25
+ :aria-live="live"
26
+ :role="live === 'off' ? undefined : 'status'"
27
+ >
28
+ <span :class="uiLoadingStatePulseClass" aria-hidden="true" data-ui-loading-pulse />
29
+ <div :class="uiLoadingStateContentClass">
30
+ <p :class="uiLoadingStateTitleClass">{{ title }}</p>
31
+ <p>{{ description }}</p>
32
+ </div>
33
+ </div>
34
+ </template>
@@ -0,0 +1,49 @@
1
+ import { cva, css } from "@styled/css";
2
+
3
+ export const segmentedControlContainerClass = css({
4
+ display: "inline-flex",
5
+ width: "fit-content",
6
+ borderRadius: "full",
7
+ borderWidth: "1px",
8
+ borderColor: "border.default",
9
+ bg: "bg.input",
10
+ padding: "1",
11
+ gap: "1",
12
+ backdropFilter: "blur(18px) saturate(140%)",
13
+ boxShadow: "inset 0 1px 0 rgba(255,255,255,0.18)",
14
+ });
15
+
16
+ export const segmentedControlOptionClass = cva({
17
+ base: {
18
+ borderRadius: "full",
19
+ px: "3.5",
20
+ py: "2",
21
+ fontSize: "sm",
22
+ fontWeight: "600",
23
+ cursor: "pointer",
24
+ borderWidth: "1px",
25
+ transition: "all 160ms ease",
26
+ },
27
+ variants: {
28
+ active: {
29
+ true: {
30
+ borderColor: "border.accent",
31
+ bg: "bg.accentStrong",
32
+ color: "text.inverse",
33
+ boxShadow: "0 14px 26px -16px rgba(49,94,255,0.68)",
34
+ _hover: {
35
+ bg: "bg.accentStrong",
36
+ },
37
+ },
38
+ false: {
39
+ borderColor: "transparent",
40
+ bg: "transparent",
41
+ color: "text.secondary",
42
+ boxShadow: "none",
43
+ _hover: {
44
+ bg: "bg.hover",
45
+ },
46
+ },
47
+ },
48
+ },
49
+ });
@@ -0,0 +1,30 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ segmentedControlContainerClass,
4
+ segmentedControlOptionClass,
5
+ } from "./UiSegmentedControl.styles";
6
+
7
+ defineProps<{
8
+ modelValue: string;
9
+ options: { label: string; value: string }[];
10
+ }>();
11
+
12
+ defineEmits<{
13
+ "update:modelValue": [string];
14
+ }>();
15
+
16
+ </script>
17
+
18
+ <template>
19
+ <div :class="segmentedControlContainerClass">
20
+ <button
21
+ v-for="option in options"
22
+ :key="option.value"
23
+ type="button"
24
+ :class="segmentedControlOptionClass({ active: option.value === modelValue })"
25
+ @click="$emit('update:modelValue', option.value)"
26
+ >
27
+ {{ option.label }}
28
+ </button>
29
+ </div>
30
+ </template>
@@ -0,0 +1,214 @@
1
+ import { cva, css } from "@styled/css";
2
+ import { dropdownRecipe } from "../styles";
3
+
4
+ export const uiSelectRootClass = cva({
5
+ base: {
6
+ position: "relative",
7
+ },
8
+ variants: {
9
+ open: {
10
+ true: { zIndex: "30" },
11
+ false: { zIndex: "1" },
12
+ },
13
+ },
14
+ defaultVariants: {
15
+ open: false,
16
+ },
17
+ });
18
+
19
+ export const uiSelectTriggerClass = cva({
20
+ base: {
21
+ width: "100%",
22
+ display: "flex",
23
+ alignItems: "center",
24
+ justifyContent: "space-between",
25
+ gap: "3",
26
+ borderWidth: "1px",
27
+ fontSize: "sm",
28
+ overflow: "hidden",
29
+ backdropFilter: "blur(24px) saturate(145%)",
30
+ transition: "all 160ms ease",
31
+ },
32
+ variants: {
33
+ size: {
34
+ sm: {
35
+ minHeight: "40px",
36
+ borderRadius: "lg",
37
+ px: "3",
38
+ py: "2.5",
39
+ },
40
+ md: {
41
+ minHeight: "48px",
42
+ borderRadius: "xl",
43
+ px: "4",
44
+ py: "3",
45
+ },
46
+ },
47
+ open: {
48
+ true: {
49
+ borderColor: "border.accent",
50
+ bg: "bg.cardStrong",
51
+ boxShadow: "0 18px 42px -28px rgba(49,94,255,0.42)",
52
+ },
53
+ false: {
54
+ borderColor: "border.default",
55
+ bg: "bg.input",
56
+ boxShadow: "inset 0 1px 0 rgba(255,255,255,0.22)",
57
+ },
58
+ },
59
+ selected: {
60
+ true: { color: "text.primary" },
61
+ false: { color: "text.muted" },
62
+ },
63
+ disabled: {
64
+ true: {
65
+ cursor: "not-allowed",
66
+ opacity: 0.55,
67
+ },
68
+ false: {
69
+ cursor: "pointer",
70
+ },
71
+ },
72
+ },
73
+ compoundVariants: [
74
+ {
75
+ disabled: false,
76
+ css: {
77
+ _hover: {
78
+ borderColor: "border.strong",
79
+ bg: "bg.cardStrong",
80
+ },
81
+ },
82
+ },
83
+ ],
84
+ defaultVariants: {
85
+ size: "md",
86
+ open: false,
87
+ selected: false,
88
+ disabled: false,
89
+ },
90
+ });
91
+
92
+ export const uiSelectMenuClass = dropdownRecipe({
93
+ placement: "anchored",
94
+ density: "cozy",
95
+ });
96
+
97
+ export const uiSelectMenuClassExtra = css({
98
+ width: "100%",
99
+ zIndex: "30",
100
+ maxHeight: "320px",
101
+ overflowY: "auto",
102
+ display: "grid",
103
+ });
104
+
105
+ export const uiSelectValueWrapClass = css({
106
+ display: "block",
107
+ textAlign: "left",
108
+ minWidth: "0",
109
+ flex: "1",
110
+ overflow: "hidden",
111
+ });
112
+
113
+ export const uiSelectValueTextClass = css({
114
+ display: "block",
115
+ overflow: "hidden",
116
+ textOverflow: "ellipsis",
117
+ whiteSpace: "nowrap",
118
+ });
119
+
120
+ export const uiSelectChevronClass = cva({
121
+ base: {
122
+ color: "text.muted",
123
+ transition: "transform 160ms ease",
124
+ },
125
+ variants: {
126
+ open: {
127
+ true: { transform: "rotate(180deg)" },
128
+ false: { transform: "rotate(0deg)" },
129
+ },
130
+ },
131
+ defaultVariants: {
132
+ open: false,
133
+ },
134
+ });
135
+
136
+ export const uiSelectOptionClass = cva({
137
+ base: {
138
+ width: "100%",
139
+ display: "flex",
140
+ alignItems: "flex-start",
141
+ justifyContent: "space-between",
142
+ gap: "3",
143
+ textAlign: "left",
144
+ borderRadius: "xl",
145
+ px: "3",
146
+ borderWidth: "1px",
147
+ cursor: "pointer",
148
+ transition: "all 140ms ease",
149
+ _hover: {
150
+ bg: "bg.selected",
151
+ borderColor: "border.accent",
152
+ },
153
+ },
154
+ variants: {
155
+ size: {
156
+ sm: { py: "2.5" },
157
+ md: { py: "3" },
158
+ },
159
+ active: {
160
+ true: {
161
+ color: "text.primary",
162
+ bg: "bg.selected",
163
+ borderColor: "border.accent",
164
+ },
165
+ false: {
166
+ color: "text.secondary",
167
+ bg: "transparent",
168
+ borderColor: "transparent",
169
+ },
170
+ },
171
+ },
172
+ defaultVariants: {
173
+ size: "md",
174
+ active: false,
175
+ },
176
+ });
177
+
178
+ export const uiSelectOptionContentClass = css({
179
+ display: "grid",
180
+ gap: "0.5",
181
+ minWidth: "0",
182
+ });
183
+
184
+ export const uiSelectOptionLabelClass = css({
185
+ fontSize: "sm",
186
+ fontWeight: "600",
187
+ minWidth: "0",
188
+ overflow: "hidden",
189
+ textOverflow: "ellipsis",
190
+ whiteSpace: "nowrap",
191
+ });
192
+
193
+ export const uiSelectOptionDescriptionClass = css({
194
+ color: "text.secondary",
195
+ fontSize: "xs",
196
+ lineHeight: "1.45",
197
+ overflowWrap: "anywhere",
198
+ });
199
+
200
+ export const uiSelectCheckClass = cva({
201
+ base: {
202
+ color: "text.accent",
203
+ transition: "opacity 140ms ease",
204
+ },
205
+ variants: {
206
+ selected: {
207
+ true: { opacity: 1 },
208
+ false: { opacity: 0 },
209
+ },
210
+ },
211
+ defaultVariants: {
212
+ selected: false,
213
+ },
214
+ });