@fragments-sdk/ui 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -2
- package/fragments.json +1 -1
- package/package.json +4 -3
- package/src/components/Accordion/Accordion.fragment.tsx +1 -1
- package/src/components/Alert/Alert.fragment.tsx +1 -1
- package/src/components/AppShell/AppShell.fragment.tsx +4 -4
- package/src/components/Avatar/Avatar.fragment.tsx +2 -2
- package/src/components/Badge/Badge.fragment.tsx +2 -2
- package/src/components/Badge/Badge.module.scss +1 -1
- package/src/components/Box/Box.fragment.tsx +1 -1
- package/src/components/Button/Button.fragment.tsx +2 -2
- package/src/components/ButtonGroup/ButtonGroup.fragment.tsx +153 -0
- package/src/components/Card/Card.fragment.tsx +1 -1
- package/src/components/Chart/Chart.fragment.tsx +213 -0
- package/src/components/Chart/Chart.module.scss +123 -0
- package/src/components/Chart/index.tsx +267 -0
- package/src/components/Checkbox/Checkbox.fragment.tsx +1 -1
- package/src/components/CodeBlock/CodeBlock.fragment.tsx +265 -6
- package/src/components/CodeBlock/CodeBlock.module.scss +141 -3
- package/src/components/CodeBlock/index.tsx +250 -36
- package/src/components/Collapsible/Collapsible.fragment.tsx +199 -0
- package/src/components/Collapsible/Collapsible.module.scss +117 -0
- package/src/components/Collapsible/index.tsx +219 -0
- package/src/components/ColorPicker/ColorPicker.fragment.tsx +196 -0
- package/src/components/ColorPicker/ColorPicker.module.scss +33 -23
- package/src/components/ColorPicker/index.tsx +34 -12
- package/src/components/Combobox/Combobox.fragment.tsx +220 -0
- package/src/components/Combobox/Combobox.module.scss +268 -0
- package/src/components/Combobox/index.tsx +398 -0
- package/src/components/ConversationList/ConversationList.fragment.tsx +202 -0
- package/src/components/ConversationList/ConversationList.module.scss +160 -0
- package/src/components/ConversationList/index.tsx +254 -0
- package/src/components/Dialog/Dialog.fragment.tsx +3 -3
- package/src/components/EmptyState/EmptyState.fragment.tsx +2 -2
- package/src/components/Field/Field.fragment.tsx +3 -3
- package/src/components/Fieldset/Fieldset.fragment.tsx +7 -7
- package/src/components/Form/Form.fragment.tsx +11 -11
- package/src/components/Grid/Grid.fragment.tsx +1 -1
- package/src/components/Header/Header.fragment.tsx +4 -4
- package/src/components/Header/Header.module.scss +9 -10
- package/src/components/Icon/Icon.fragment.tsx +2 -2
- package/src/components/Image/Image.fragment.tsx +2 -2
- package/src/components/Input/Input.fragment.tsx +1 -1
- package/src/components/Input/Input.module.scss +2 -2
- package/src/components/Link/Link.fragment.tsx +1 -1
- package/src/components/List/List.fragment.tsx +2 -2
- package/src/components/Listbox/Listbox.fragment.tsx +1 -1
- package/src/components/Loading/Loading.fragment.tsx +153 -0
- package/src/components/Loading/Loading.module.scss +256 -0
- package/src/components/Loading/index.tsx +236 -0
- package/src/components/Menu/Menu.fragment.tsx +3 -3
- package/src/components/Message/Message.fragment.tsx +200 -0
- package/src/components/Message/Message.module.scss +224 -0
- package/src/components/Message/index.tsx +278 -0
- package/src/components/Popover/Popover.fragment.tsx +4 -4
- package/src/components/Progress/Progress.fragment.tsx +1 -1
- package/src/components/Prompt/Prompt.fragment.tsx +2 -2
- package/src/components/RadioGroup/RadioGroup.fragment.tsx +1 -1
- package/src/components/RadioGroup/RadioGroup.module.scss +7 -4
- package/src/components/Select/Select.fragment.tsx +1 -1
- package/src/components/Select/Select.module.scss +8 -0
- package/src/components/Select/index.tsx +85 -5
- package/src/components/Separator/Separator.fragment.tsx +1 -1
- package/src/components/Sidebar/Sidebar.fragment.tsx +2 -2
- package/src/components/Sidebar/Sidebar.module.scss +19 -0
- package/src/components/Sidebar/index.tsx +52 -11
- package/src/components/Skeleton/Skeleton.fragment.tsx +1 -1
- package/src/components/Slider/Slider.fragment.tsx +201 -0
- package/src/components/Stack/Stack.fragment.tsx +194 -0
- package/src/components/Table/Table.fragment.tsx +3 -3
- package/src/components/Tabs/Tabs.fragment.tsx +1 -1
- package/src/components/Tabs/Tabs.module.scss +2 -2
- package/src/components/Text/Text.fragment.tsx +188 -0
- package/src/components/Textarea/Textarea.fragment.tsx +1 -1
- package/src/components/Theme/Theme.fragment.tsx +2 -2
- package/src/components/Theme/ThemeToggle.module.scss +13 -13
- package/src/components/ThinkingIndicator/ThinkingIndicator.fragment.tsx +182 -0
- package/src/components/ThinkingIndicator/ThinkingIndicator.module.scss +226 -0
- package/src/components/ThinkingIndicator/index.tsx +258 -0
- package/src/components/Toast/Toast.fragment.tsx +1 -1
- package/src/components/Toggle/Toggle.fragment.tsx +1 -1
- package/src/components/ToggleGroup/ToggleGroup.fragment.tsx +207 -0
- package/src/components/Tooltip/Tooltip.fragment.tsx +3 -3
- package/src/components/VisuallyHidden/VisuallyHidden.fragment.tsx +2 -2
- package/src/index.ts +99 -3
- package/src/recipes/AIChat.recipe.ts +266 -0
- package/src/tokens/_computed.scss +212 -0
- package/src/tokens/_density.scss +171 -0
- package/src/tokens/_derive.scss +287 -0
- package/src/tokens/_index.scss +39 -1
- package/src/tokens/_mixins.scss +41 -0
- package/src/tokens/_palettes.scss +185 -0
- package/src/tokens/_radius.scss +107 -0
- package/src/tokens/_seeds.scss +59 -0
- package/src/tokens/_variables.scss +171 -130
- package/src/components/ColorChip/ColorChip.module.scss +0 -165
- package/src/components/ColorChip/index.tsx +0 -157
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { defineSegment } from '@fragments/core';
|
|
3
|
-
import { Form } from '
|
|
4
|
-
import { Field } from '../Field
|
|
5
|
-
import { Fieldset } from '../Fieldset
|
|
6
|
-
import { Input } from '../Input
|
|
7
|
-
import { Textarea } from '../Textarea
|
|
8
|
-
import { Select } from '../Select
|
|
9
|
-
import { Checkbox } from '../Checkbox
|
|
10
|
-
import { RadioGroup } from '../RadioGroup
|
|
11
|
-
import { Toggle } from '../Toggle
|
|
12
|
-
import { Button } from '../Button
|
|
13
|
-
import { Grid } from '../Grid
|
|
3
|
+
import { Form } from '.';
|
|
4
|
+
import { Field } from '../Field';
|
|
5
|
+
import { Fieldset } from '../Fieldset';
|
|
6
|
+
import { Input } from '../Input';
|
|
7
|
+
import { Textarea } from '../Textarea';
|
|
8
|
+
import { Select } from '../Select';
|
|
9
|
+
import { Checkbox } from '../Checkbox';
|
|
10
|
+
import { RadioGroup } from '../RadioGroup';
|
|
11
|
+
import { Toggle } from '../Toggle';
|
|
12
|
+
import { Button } from '../Button';
|
|
13
|
+
import { Grid } from '../Grid';
|
|
14
14
|
|
|
15
15
|
export default defineSegment({
|
|
16
16
|
component: Form,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { defineSegment } from '@fragments/core';
|
|
3
|
-
import { Header } from '
|
|
4
|
-
import { ThemeToggle, ThemeProvider } from '../Theme
|
|
5
|
-
import { Button } from '../Button
|
|
6
|
-
import { Input } from '../Input
|
|
3
|
+
import { Header } from '.';
|
|
4
|
+
import { ThemeToggle, ThemeProvider } from '../Theme';
|
|
5
|
+
import { Button } from '../Button';
|
|
6
|
+
import { Input } from '../Input';
|
|
7
7
|
|
|
8
8
|
function SearchIcon() {
|
|
9
9
|
return (
|
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
.header {
|
|
9
9
|
display: flex;
|
|
10
10
|
align-items: center;
|
|
11
|
-
height: var(--header-height,
|
|
12
|
-
min-height: var(--header-height,
|
|
11
|
+
height: var(--header-height, var(--fui-appshell-header-height, $fui-appshell-header-height));
|
|
12
|
+
min-height: var(--header-height, var(--fui-appshell-header-height, $fui-appshell-header-height));
|
|
13
13
|
background-color: var(--fui-bg-primary, $fui-bg-primary);
|
|
14
14
|
padding: 0 var(--fui-space-4, $fui-space-4);
|
|
15
|
-
z-index: var(--fui-header-z-index,
|
|
15
|
+
z-index: var(--fui-header-z-index, $fui-header-z-index);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
.fixed {
|
|
19
|
-
position:
|
|
19
|
+
position: sticky;
|
|
20
20
|
top: 0;
|
|
21
21
|
left: 0;
|
|
22
22
|
right: 0;
|
|
@@ -55,7 +55,6 @@
|
|
|
55
55
|
|
|
56
56
|
img,
|
|
57
57
|
svg {
|
|
58
|
-
height: 32px;
|
|
59
58
|
width: auto;
|
|
60
59
|
}
|
|
61
60
|
}
|
|
@@ -94,7 +93,7 @@
|
|
|
94
93
|
color: var(--fui-text-secondary, $fui-text-secondary);
|
|
95
94
|
text-decoration: none;
|
|
96
95
|
white-space: nowrap;
|
|
97
|
-
min-height:
|
|
96
|
+
min-height: var(--fui-button-height-md, $fui-button-height-md);
|
|
98
97
|
|
|
99
98
|
&:hover {
|
|
100
99
|
background-color: var(--fui-bg-hover, $fui-bg-hover);
|
|
@@ -151,8 +150,8 @@
|
|
|
151
150
|
display: flex;
|
|
152
151
|
align-items: center;
|
|
153
152
|
justify-content: center;
|
|
154
|
-
width:
|
|
155
|
-
height:
|
|
153
|
+
width: var(--fui-touch-lg, $fui-touch-lg);
|
|
154
|
+
height: var(--fui-touch-lg, $fui-touch-lg);
|
|
156
155
|
border-radius: var(--fui-radius-md, $fui-radius-md);
|
|
157
156
|
color: var(--fui-text-primary, $fui-text-primary);
|
|
158
157
|
flex-shrink: 0;
|
|
@@ -162,8 +161,8 @@
|
|
|
162
161
|
}
|
|
163
162
|
|
|
164
163
|
svg {
|
|
165
|
-
width:
|
|
166
|
-
height:
|
|
164
|
+
width: var(--fui-icon-xl, $fui-icon-xl);
|
|
165
|
+
height: var(--fui-icon-xl, $fui-icon-xl);
|
|
167
166
|
}
|
|
168
167
|
}
|
|
169
168
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { defineSegment } from '@fragments/core';
|
|
3
|
-
import { Icon } from '
|
|
3
|
+
import { Icon } from '.';
|
|
4
4
|
import { Heart, Star, Check, Warning, Info } from '@phosphor-icons/react';
|
|
5
5
|
|
|
6
6
|
export default defineSegment({
|
|
@@ -9,7 +9,7 @@ export default defineSegment({
|
|
|
9
9
|
meta: {
|
|
10
10
|
name: 'Icon',
|
|
11
11
|
description: 'Wrapper for Phosphor icons with consistent sizing and semantic colors. Provides standardized icon rendering across the design system.',
|
|
12
|
-
category: '
|
|
12
|
+
category: 'display',
|
|
13
13
|
status: 'stable',
|
|
14
14
|
tags: ['icon', 'phosphor', 'visual', 'symbol', 'graphic'],
|
|
15
15
|
since: '0.1.0',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { defineSegment } from '@fragments/core';
|
|
3
|
-
import { Image } from '
|
|
3
|
+
import { Image } from '.';
|
|
4
4
|
|
|
5
5
|
export default defineSegment({
|
|
6
6
|
component: Image,
|
|
@@ -8,7 +8,7 @@ export default defineSegment({
|
|
|
8
8
|
meta: {
|
|
9
9
|
name: 'Image',
|
|
10
10
|
description: 'Responsive image component with aspect ratio control, loading states, and error fallbacks. Handles image display with consistent styling.',
|
|
11
|
-
category: '
|
|
11
|
+
category: 'display',
|
|
12
12
|
status: 'stable',
|
|
13
13
|
tags: ['image', 'media', 'photo', 'picture', 'visual'],
|
|
14
14
|
since: '0.1.0',
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
// Size variants
|
|
45
45
|
.sm {
|
|
46
|
-
height: var(--fui-
|
|
46
|
+
height: var(--fui-input-height-sm, $fui-input-height-sm);
|
|
47
47
|
padding: 0 var(--fui-space-2, $fui-space-2);
|
|
48
48
|
font-size: var(--fui-font-size-xs, $fui-font-size-xs);
|
|
49
49
|
}
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
.lg {
|
|
58
|
-
height: var(--fui-
|
|
58
|
+
height: var(--fui-input-height-lg, $fui-input-height-lg);
|
|
59
59
|
padding: 0 var(--fui-space-4, $fui-space-4);
|
|
60
60
|
font-size: var(--fui-font-size-base, $fui-font-size-base);
|
|
61
61
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { defineSegment } from '@fragments/core';
|
|
3
|
-
import { List } from '
|
|
3
|
+
import { List } from '.';
|
|
4
4
|
import { Check, Star, ArrowRight } from '@phosphor-icons/react';
|
|
5
5
|
|
|
6
6
|
export default defineSegment({
|
|
@@ -9,7 +9,7 @@ export default defineSegment({
|
|
|
9
9
|
meta: {
|
|
10
10
|
name: 'List',
|
|
11
11
|
description: 'Compound component for rendering ordered or unordered lists with consistent styling. Supports bullet, numbered, and icon-prefixed items.',
|
|
12
|
-
category: '
|
|
12
|
+
category: 'display',
|
|
13
13
|
status: 'stable',
|
|
14
14
|
tags: ['list', 'items', 'bullet', 'ordered', 'unordered'],
|
|
15
15
|
since: '0.1.0',
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { defineSegment } from '@fragments/core';
|
|
3
|
+
import { Loading } from '.';
|
|
4
|
+
|
|
5
|
+
export default defineSegment({
|
|
6
|
+
component: Loading,
|
|
7
|
+
|
|
8
|
+
meta: {
|
|
9
|
+
name: 'Loading',
|
|
10
|
+
description: 'Versatile loading indicator with multiple variants for showing progress or waiting states',
|
|
11
|
+
category: 'feedback',
|
|
12
|
+
status: 'stable',
|
|
13
|
+
tags: ['loading', 'spinner', 'progress', 'feedback', 'indicator', 'async'],
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
usage: {
|
|
17
|
+
when: [
|
|
18
|
+
'Indicating content is being fetched or processed',
|
|
19
|
+
'Showing a pending state while waiting for an async operation',
|
|
20
|
+
'Displaying loading state for buttons, forms, or page sections',
|
|
21
|
+
'Full-screen loading during initial app/page load',
|
|
22
|
+
],
|
|
23
|
+
whenNot: [
|
|
24
|
+
'For showing determinate progress - use Progress component instead',
|
|
25
|
+
'For showing skeleton placeholders - use Skeleton component instead',
|
|
26
|
+
'For AI-specific thinking states - use ThinkingIndicator instead',
|
|
27
|
+
],
|
|
28
|
+
guidelines: [
|
|
29
|
+
'Use spinner variant for general loading states',
|
|
30
|
+
'Use dots variant for chat/messaging contexts',
|
|
31
|
+
'Use pulse variant for subtle, ambient loading',
|
|
32
|
+
'Always provide a meaningful label for screen readers',
|
|
33
|
+
'Consider using Loading.Screen for initial page loads',
|
|
34
|
+
'Use Loading.Inline when loading indicator should flow with text',
|
|
35
|
+
],
|
|
36
|
+
accessibility: [
|
|
37
|
+
'Component uses role="status" and aria-live="polite"',
|
|
38
|
+
'Always provide descriptive label prop for screen readers',
|
|
39
|
+
'Animations respect prefers-reduced-motion preference',
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
props: {
|
|
44
|
+
size: {
|
|
45
|
+
type: 'enum',
|
|
46
|
+
values: ['sm', 'md', 'lg', 'xl'],
|
|
47
|
+
default: 'md',
|
|
48
|
+
description: 'Size of the loading indicator',
|
|
49
|
+
},
|
|
50
|
+
variant: {
|
|
51
|
+
type: 'enum',
|
|
52
|
+
values: ['spinner', 'dots', 'pulse'],
|
|
53
|
+
default: 'spinner',
|
|
54
|
+
description: 'Visual style of the loading animation',
|
|
55
|
+
},
|
|
56
|
+
label: {
|
|
57
|
+
type: 'string',
|
|
58
|
+
default: 'Loading...',
|
|
59
|
+
description: 'Accessible label for screen readers',
|
|
60
|
+
},
|
|
61
|
+
centered: {
|
|
62
|
+
type: 'boolean',
|
|
63
|
+
default: false,
|
|
64
|
+
description: 'Whether to center the loading indicator in its container',
|
|
65
|
+
},
|
|
66
|
+
fill: {
|
|
67
|
+
type: 'boolean',
|
|
68
|
+
default: false,
|
|
69
|
+
description: 'Whether to fill the parent container',
|
|
70
|
+
},
|
|
71
|
+
overlay: {
|
|
72
|
+
type: 'boolean',
|
|
73
|
+
default: false,
|
|
74
|
+
description: 'Whether to show with a backdrop overlay',
|
|
75
|
+
},
|
|
76
|
+
color: {
|
|
77
|
+
type: 'enum',
|
|
78
|
+
values: ['accent', 'current', 'muted'],
|
|
79
|
+
default: 'accent',
|
|
80
|
+
description: 'Color variant - accent uses theme color, current inherits text color',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
variants: [
|
|
85
|
+
{
|
|
86
|
+
name: 'Default',
|
|
87
|
+
description: 'Default spinner loading indicator',
|
|
88
|
+
render: () => <Loading />,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'Sizes',
|
|
92
|
+
description: 'Loading indicators in different sizes',
|
|
93
|
+
render: () => (
|
|
94
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '24px' }}>
|
|
95
|
+
<Loading size="sm" />
|
|
96
|
+
<Loading size="md" />
|
|
97
|
+
<Loading size="lg" />
|
|
98
|
+
<Loading size="xl" />
|
|
99
|
+
</div>
|
|
100
|
+
),
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'Dots',
|
|
104
|
+
description: 'Bouncing dots animation',
|
|
105
|
+
render: () => <Loading variant="dots" />,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'Pulse',
|
|
109
|
+
description: 'Pulsing circle animation',
|
|
110
|
+
render: () => <Loading variant="pulse" />,
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: 'Colors',
|
|
114
|
+
description: 'Different color variants',
|
|
115
|
+
render: () => (
|
|
116
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '24px' }}>
|
|
117
|
+
<Loading color="accent" />
|
|
118
|
+
<Loading color="muted" />
|
|
119
|
+
<span style={{ color: '#3b82f6' }}>
|
|
120
|
+
<Loading color="current" />
|
|
121
|
+
</span>
|
|
122
|
+
</div>
|
|
123
|
+
),
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: 'Inline',
|
|
127
|
+
description: 'Inline loading indicator that flows with text',
|
|
128
|
+
render: () => (
|
|
129
|
+
<p style={{ margin: 0 }}>
|
|
130
|
+
Processing your request <Loading.Inline /> please wait...
|
|
131
|
+
</p>
|
|
132
|
+
),
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: 'Centered',
|
|
136
|
+
description: 'Centered in container',
|
|
137
|
+
render: () => (
|
|
138
|
+
<div style={{ width: '200px', height: '100px', border: '1px dashed #ccc', borderRadius: '8px' }}>
|
|
139
|
+
<Loading centered fill />
|
|
140
|
+
</div>
|
|
141
|
+
),
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: 'Screen',
|
|
145
|
+
description: 'Full-screen loading state with optional label',
|
|
146
|
+
render: () => (
|
|
147
|
+
<div style={{ position: 'relative', width: '300px', height: '200px', border: '1px solid #ccc', borderRadius: '8px', overflow: 'hidden' }}>
|
|
148
|
+
<Loading.Screen size="lg" label="Loading application..." showLabel />
|
|
149
|
+
</div>
|
|
150
|
+
),
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
});
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
@use '../../tokens/variables' as *;
|
|
2
|
+
@use '../../tokens/mixins' as *;
|
|
3
|
+
|
|
4
|
+
// ============================================
|
|
5
|
+
// Loading Base
|
|
6
|
+
// ============================================
|
|
7
|
+
|
|
8
|
+
.loading {
|
|
9
|
+
display: inline-flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
flex-shrink: 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// ============================================
|
|
16
|
+
// Sizes
|
|
17
|
+
// ============================================
|
|
18
|
+
|
|
19
|
+
.sm {
|
|
20
|
+
--loading-size: #{$fui-icon-sm}; // 14px
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.md {
|
|
24
|
+
--loading-size: #{$fui-icon-lg}; // 20px
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.lg {
|
|
28
|
+
--loading-size: #{$fui-icon-xl}; // 24px
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.xl {
|
|
32
|
+
--loading-size: 2.286rem; // 32px
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ============================================
|
|
36
|
+
// Colors
|
|
37
|
+
// ============================================
|
|
38
|
+
|
|
39
|
+
.color-accent {
|
|
40
|
+
color: var(--fui-color-accent, $fui-color-accent);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.color-current {
|
|
44
|
+
color: currentColor;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.color-muted {
|
|
48
|
+
color: var(--fui-text-tertiary, $fui-text-tertiary);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ============================================
|
|
52
|
+
// Layout Modifiers
|
|
53
|
+
// ============================================
|
|
54
|
+
|
|
55
|
+
.centered {
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
justify-content: center;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.fill {
|
|
62
|
+
width: 100%;
|
|
63
|
+
height: 100%;
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
justify-content: center;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ============================================
|
|
70
|
+
// Spinner Variant
|
|
71
|
+
// ============================================
|
|
72
|
+
|
|
73
|
+
.spinnerIcon {
|
|
74
|
+
width: var(--loading-size);
|
|
75
|
+
height: var(--loading-size);
|
|
76
|
+
animation: spin 0.8s linear infinite;
|
|
77
|
+
|
|
78
|
+
@media (prefers-reduced-motion: reduce) {
|
|
79
|
+
animation: none;
|
|
80
|
+
opacity: 0.7;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@keyframes spin {
|
|
85
|
+
from {
|
|
86
|
+
transform: rotate(0deg);
|
|
87
|
+
}
|
|
88
|
+
to {
|
|
89
|
+
transform: rotate(360deg);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ============================================
|
|
94
|
+
// Dots Variant
|
|
95
|
+
// ============================================
|
|
96
|
+
|
|
97
|
+
.dots {
|
|
98
|
+
display: flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
gap: calc(var(--loading-size) * 0.3);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.dot {
|
|
104
|
+
width: calc(var(--loading-size) * 0.35);
|
|
105
|
+
height: calc(var(--loading-size) * 0.35);
|
|
106
|
+
border-radius: var(--fui-radius-full, $fui-radius-full);
|
|
107
|
+
background-color: currentColor;
|
|
108
|
+
animation: bounce 1.4s ease-in-out infinite;
|
|
109
|
+
|
|
110
|
+
&:nth-child(1) {
|
|
111
|
+
animation-delay: 0s;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
&:nth-child(2) {
|
|
115
|
+
animation-delay: 0.2s;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
&:nth-child(3) {
|
|
119
|
+
animation-delay: 0.4s;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@media (prefers-reduced-motion: reduce) {
|
|
123
|
+
animation: none;
|
|
124
|
+
opacity: 0.6;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@keyframes bounce {
|
|
129
|
+
0%,
|
|
130
|
+
60%,
|
|
131
|
+
100% {
|
|
132
|
+
transform: translateY(0);
|
|
133
|
+
opacity: 0.4;
|
|
134
|
+
}
|
|
135
|
+
30% {
|
|
136
|
+
transform: translateY(-30%);
|
|
137
|
+
opacity: 1;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ============================================
|
|
142
|
+
// Pulse Variant
|
|
143
|
+
// ============================================
|
|
144
|
+
|
|
145
|
+
.pulse {
|
|
146
|
+
position: relative;
|
|
147
|
+
width: var(--loading-size);
|
|
148
|
+
height: var(--loading-size);
|
|
149
|
+
display: flex;
|
|
150
|
+
align-items: center;
|
|
151
|
+
justify-content: center;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.pulseRing {
|
|
155
|
+
position: absolute;
|
|
156
|
+
width: 100%;
|
|
157
|
+
height: 100%;
|
|
158
|
+
border-radius: var(--fui-radius-full, $fui-radius-full);
|
|
159
|
+
background-color: currentColor;
|
|
160
|
+
opacity: 0.3;
|
|
161
|
+
animation: pulseRing 1.5s ease-out infinite;
|
|
162
|
+
|
|
163
|
+
@media (prefers-reduced-motion: reduce) {
|
|
164
|
+
animation: none;
|
|
165
|
+
opacity: 0.2;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.pulseDot {
|
|
170
|
+
width: 50%;
|
|
171
|
+
height: 50%;
|
|
172
|
+
border-radius: var(--fui-radius-full, $fui-radius-full);
|
|
173
|
+
background-color: currentColor;
|
|
174
|
+
z-index: 1;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@keyframes pulseRing {
|
|
178
|
+
0% {
|
|
179
|
+
transform: scale(0.5);
|
|
180
|
+
opacity: 0.5;
|
|
181
|
+
}
|
|
182
|
+
100% {
|
|
183
|
+
transform: scale(1.5);
|
|
184
|
+
opacity: 0;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ============================================
|
|
189
|
+
// Overlay
|
|
190
|
+
// ============================================
|
|
191
|
+
|
|
192
|
+
.overlayBackdrop {
|
|
193
|
+
position: absolute;
|
|
194
|
+
inset: 0;
|
|
195
|
+
display: flex;
|
|
196
|
+
align-items: center;
|
|
197
|
+
justify-content: center;
|
|
198
|
+
background-color: var(--fui-backdrop, $fui-backdrop);
|
|
199
|
+
z-index: 50;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.overlay {
|
|
203
|
+
// Additional styling if needed when in overlay mode
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ============================================
|
|
207
|
+
// Inline Variant
|
|
208
|
+
// ============================================
|
|
209
|
+
|
|
210
|
+
.inline {
|
|
211
|
+
display: inline-flex;
|
|
212
|
+
align-items: center;
|
|
213
|
+
vertical-align: middle;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.inline-sm {
|
|
217
|
+
--inline-size: 0.875em; // Relative to surrounding text
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.inline-md {
|
|
221
|
+
--inline-size: 1.125em;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.inlineSpinner {
|
|
225
|
+
width: var(--inline-size);
|
|
226
|
+
height: var(--inline-size);
|
|
227
|
+
animation: spin 0.8s linear infinite;
|
|
228
|
+
color: currentColor;
|
|
229
|
+
|
|
230
|
+
@media (prefers-reduced-motion: reduce) {
|
|
231
|
+
animation: none;
|
|
232
|
+
opacity: 0.7;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ============================================
|
|
237
|
+
// Screen (Full-screen loading)
|
|
238
|
+
// ============================================
|
|
239
|
+
|
|
240
|
+
.screen {
|
|
241
|
+
position: fixed;
|
|
242
|
+
inset: 0;
|
|
243
|
+
display: flex;
|
|
244
|
+
flex-direction: column;
|
|
245
|
+
align-items: center;
|
|
246
|
+
justify-content: center;
|
|
247
|
+
gap: var(--fui-space-3, $fui-space-3);
|
|
248
|
+
background-color: var(--fui-bg-primary, $fui-bg-primary);
|
|
249
|
+
z-index: 100;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.screenLabel {
|
|
253
|
+
@include text-base;
|
|
254
|
+
font-size: var(--fui-font-size-sm, $fui-font-size-sm);
|
|
255
|
+
color: var(--fui-text-secondary, $fui-text-secondary);
|
|
256
|
+
}
|