@groundbrick/svelte-ui 0.1.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/README.md +125 -0
- package/dist/components/Alert.svelte +335 -0
- package/dist/components/Alert.svelte.d.ts +24 -0
- package/dist/components/AutocompleteInput.svelte +356 -0
- package/dist/components/AutocompleteInput.svelte.d.ts +72 -0
- package/dist/components/Badge.svelte +185 -0
- package/dist/components/Badge.svelte.d.ts +20 -0
- package/dist/components/Button.svelte +415 -0
- package/dist/components/Button.svelte.d.ts +34 -0
- package/dist/components/Card.svelte +181 -0
- package/dist/components/Card.svelte.d.ts +24 -0
- package/dist/components/CardBody.svelte +78 -0
- package/dist/components/CardBody.svelte.d.ts +12 -0
- package/dist/components/CardFooter.svelte +81 -0
- package/dist/components/CardFooter.svelte.d.ts +14 -0
- package/dist/components/CardHeader.svelte +186 -0
- package/dist/components/CardHeader.svelte.d.ts +21 -0
- package/dist/components/Col.svelte +172 -0
- package/dist/components/Col.svelte.d.ts +26 -0
- package/dist/components/Container.svelte +118 -0
- package/dist/components/Container.svelte.d.ts +14 -0
- package/dist/components/Drawer.svelte +233 -0
- package/dist/components/Drawer.svelte.d.ts +13 -0
- package/dist/components/Dropdown.svelte +190 -0
- package/dist/components/Dropdown.svelte.d.ts +26 -0
- package/dist/components/DropdownItem.svelte +103 -0
- package/dist/components/DropdownItem.svelte.d.ts +22 -0
- package/dist/components/DurationInput.svelte +170 -0
- package/dist/components/DurationInput.svelte.d.ts +27 -0
- package/dist/components/EditableTable.svelte +647 -0
- package/dist/components/EditableTable.svelte.d.ts +74 -0
- package/dist/components/EmptyState.svelte +192 -0
- package/dist/components/EmptyState.svelte.d.ts +22 -0
- package/dist/components/FormField.svelte +260 -0
- package/dist/components/FormField.svelte.d.ts +68 -0
- package/dist/components/GridView.svelte +1022 -0
- package/dist/components/GridView.svelte.d.ts +38 -0
- package/dist/components/GridView.types.d.ts +28 -0
- package/dist/components/GridView.types.js +1 -0
- package/dist/components/LoadingSpinner.svelte +253 -0
- package/dist/components/LoadingSpinner.svelte.d.ts +17 -0
- package/dist/components/Modal.svelte +473 -0
- package/dist/components/Modal.svelte.d.ts +42 -0
- package/dist/components/PhoneInput.svelte +406 -0
- package/dist/components/PhoneInput.svelte.d.ts +31 -0
- package/dist/components/PhotoUpload.svelte +529 -0
- package/dist/components/PhotoUpload.svelte.d.ts +46 -0
- package/dist/components/Row.svelte +153 -0
- package/dist/components/Row.svelte.d.ts +18 -0
- package/dist/icons/PawPrintIcon.svelte +41 -0
- package/dist/icons/PawPrintIcon.svelte.d.ts +14 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +49 -0
- package/dist/styles/forms.css +182 -0
- package/dist/styles/tokens.css +243 -0
- package/dist/utils/duration.d.ts +20 -0
- package/dist/utils/duration.js +40 -0
- package/dist/utils/scrollLock.d.ts +7 -0
- package/dist/utils/scrollLock.js +26 -0
- package/package.json +66 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
|
|
4
|
+
interface RowProps {
|
|
5
|
+
/** Gap entre colunas */
|
|
6
|
+
gap?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
7
|
+
/** Alinhamento vertical */
|
|
8
|
+
align?: 'start' | 'center' | 'end' | 'stretch' | 'baseline';
|
|
9
|
+
/** Justificação horizontal */
|
|
10
|
+
justify?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly';
|
|
11
|
+
/** Wrap das colunas */
|
|
12
|
+
wrap?: boolean;
|
|
13
|
+
/** Conteúdo do row */
|
|
14
|
+
children?: Snippet;
|
|
15
|
+
/** Classes CSS adicionais */
|
|
16
|
+
class?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
gap = 'none',
|
|
21
|
+
align = 'start',
|
|
22
|
+
justify = 'start',
|
|
23
|
+
wrap = true,
|
|
24
|
+
children,
|
|
25
|
+
class: additionalClasses = ''
|
|
26
|
+
}: RowProps = $props();
|
|
27
|
+
|
|
28
|
+
const gapClasses: Record<string, string> = {
|
|
29
|
+
none: '',
|
|
30
|
+
xs: 'gap-1',
|
|
31
|
+
sm: 'gap-2',
|
|
32
|
+
md: 'gap-3',
|
|
33
|
+
lg: 'gap-4',
|
|
34
|
+
xl: 'gap-5'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const alignClasses: Record<string, string> = {
|
|
38
|
+
start: 'align-items-start',
|
|
39
|
+
center: 'align-items-center',
|
|
40
|
+
end: 'align-items-end',
|
|
41
|
+
stretch: 'align-items-stretch',
|
|
42
|
+
baseline: 'align-items-baseline'
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const justifyClasses: Record<string, string> = {
|
|
46
|
+
start: 'justify-content-start',
|
|
47
|
+
center: 'justify-content-center',
|
|
48
|
+
end: 'justify-content-end',
|
|
49
|
+
between: 'justify-content-between',
|
|
50
|
+
around: 'justify-content-around',
|
|
51
|
+
evenly: 'justify-content-evenly'
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const rowClass = [
|
|
55
|
+
'row',
|
|
56
|
+
gapClasses[gap],
|
|
57
|
+
alignClasses[align],
|
|
58
|
+
justifyClasses[justify],
|
|
59
|
+
!wrap ? 'flex-nowrap' : '',
|
|
60
|
+
additionalClasses
|
|
61
|
+
].filter(Boolean).join(' ');
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<div class={rowClass}>
|
|
65
|
+
{@render children?.()}
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<style>
|
|
69
|
+
.row {
|
|
70
|
+
display: flex;
|
|
71
|
+
flex-wrap: wrap;
|
|
72
|
+
/* Use Bootstrap's native gutter system - remove custom margins */
|
|
73
|
+
margin-left: -12px;
|
|
74
|
+
margin-right: -12px;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.row > :global(*) {
|
|
78
|
+
/* Use Bootstrap's native gutter system - remove custom padding */
|
|
79
|
+
padding-left: 12px;
|
|
80
|
+
padding-right: 12px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* Gap Classes */
|
|
84
|
+
.gap-1 {
|
|
85
|
+
gap: var(--spacing-xs);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.gap-2 {
|
|
89
|
+
gap: var(--spacing-sm);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.gap-3 {
|
|
93
|
+
gap: var(--spacing-md);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.gap-4 {
|
|
97
|
+
gap: var(--spacing-lg);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.gap-5 {
|
|
101
|
+
gap: var(--spacing-xl);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Alignment */
|
|
105
|
+
.align-items-start {
|
|
106
|
+
align-items: flex-start;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.align-items-center {
|
|
110
|
+
align-items: center;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.align-items-end {
|
|
114
|
+
align-items: flex-end;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.align-items-stretch {
|
|
118
|
+
align-items: stretch;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.align-items-baseline {
|
|
122
|
+
align-items: baseline;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* Justification */
|
|
126
|
+
.justify-content-start {
|
|
127
|
+
justify-content: flex-start;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.justify-content-center {
|
|
131
|
+
justify-content: center;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.justify-content-end {
|
|
135
|
+
justify-content: flex-end;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.justify-content-between {
|
|
139
|
+
justify-content: space-between;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.justify-content-around {
|
|
143
|
+
justify-content: space-around;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.justify-content-evenly {
|
|
147
|
+
justify-content: space-evenly;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.flex-nowrap {
|
|
151
|
+
flex-wrap: nowrap;
|
|
152
|
+
}
|
|
153
|
+
</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
interface RowProps {
|
|
3
|
+
/** Gap entre colunas */
|
|
4
|
+
gap?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
5
|
+
/** Alinhamento vertical */
|
|
6
|
+
align?: 'start' | 'center' | 'end' | 'stretch' | 'baseline';
|
|
7
|
+
/** Justificação horizontal */
|
|
8
|
+
justify?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly';
|
|
9
|
+
/** Wrap das colunas */
|
|
10
|
+
wrap?: boolean;
|
|
11
|
+
/** Conteúdo do row */
|
|
12
|
+
children?: Snippet;
|
|
13
|
+
/** Classes CSS adicionais */
|
|
14
|
+
class?: string;
|
|
15
|
+
}
|
|
16
|
+
declare const Row: import("svelte").Component<RowProps, {}, "">;
|
|
17
|
+
type Row = ReturnType<typeof Row>;
|
|
18
|
+
export default Row;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Width/height. Accepts number (px) or CSS string. Default "1em" so the
|
|
4
|
+
* icon scales with the parent's font-size, mirroring `<i class="bi …">`. */
|
|
5
|
+
size?: number | string;
|
|
6
|
+
/** Stroke width — Lucide's default is 2. */
|
|
7
|
+
strokeWidth?: number;
|
|
8
|
+
class?: string;
|
|
9
|
+
/** Provide an accessible title only when the icon is the sole semantic
|
|
10
|
+
* indicator. Otherwise the icon stays aria-hidden. */
|
|
11
|
+
title?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
size = "1em",
|
|
16
|
+
strokeWidth = 2,
|
|
17
|
+
class: className = "",
|
|
18
|
+
title,
|
|
19
|
+
}: Props = $props();
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<svg
|
|
23
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
24
|
+
width={size}
|
|
25
|
+
height={size}
|
|
26
|
+
viewBox="0 0 24 24"
|
|
27
|
+
fill="none"
|
|
28
|
+
stroke="currentColor"
|
|
29
|
+
stroke-width={strokeWidth}
|
|
30
|
+
stroke-linecap="round"
|
|
31
|
+
stroke-linejoin="round"
|
|
32
|
+
class={className}
|
|
33
|
+
role={title ? "img" : "presentation"}
|
|
34
|
+
aria-hidden={title ? undefined : "true"}
|
|
35
|
+
>
|
|
36
|
+
{#if title}<title>{title}</title>{/if}
|
|
37
|
+
<circle cx="11" cy="4" r="2" />
|
|
38
|
+
<circle cx="18" cy="8" r="2" />
|
|
39
|
+
<circle cx="20" cy="16" r="2" />
|
|
40
|
+
<path d="M9 10a5 5 0 0 1 5 5v3.5a3.5 3.5 0 0 1-6.84 1.045Q6.52 17.48 4.46 16.84A3.5 3.5 0 0 1 5.5 10Z" />
|
|
41
|
+
</svg>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
/** Width/height. Accepts number (px) or CSS string. Default "1em" so the
|
|
3
|
+
* icon scales with the parent's font-size, mirroring `<i class="bi …">`. */
|
|
4
|
+
size?: number | string;
|
|
5
|
+
/** Stroke width — Lucide's default is 2. */
|
|
6
|
+
strokeWidth?: number;
|
|
7
|
+
class?: string;
|
|
8
|
+
/** Provide an accessible title only when the icon is the sole semantic
|
|
9
|
+
* indicator. Otherwise the icon stays aria-hidden. */
|
|
10
|
+
title?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const PawPrintIcon: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type PawPrintIcon = ReturnType<typeof PawPrintIcon>;
|
|
14
|
+
export default PawPrintIcon;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @groundbrick/svelte-ui
|
|
3
|
+
* Reusable Svelte 5 UI components (design system).
|
|
4
|
+
*
|
|
5
|
+
* Import the default theme tokens via `@groundbrick/svelte-ui/styles/tokens.css`
|
|
6
|
+
* and override CSS variables (globally or on a wrapper element) to re-theme.
|
|
7
|
+
*
|
|
8
|
+
* Components assume Bootstrap 5 CSS/JS and Bootstrap Icons are loaded by the
|
|
9
|
+
* consuming app (declared as optional peer dependencies).
|
|
10
|
+
*/
|
|
11
|
+
export declare const VERSION = "0.1.0";
|
|
12
|
+
export { default as Button } from './components/Button.svelte';
|
|
13
|
+
export { default as Dropdown } from './components/Dropdown.svelte';
|
|
14
|
+
export { default as DropdownItem } from './components/DropdownItem.svelte';
|
|
15
|
+
export { default as Card } from './components/Card.svelte';
|
|
16
|
+
export { default as CardHeader } from './components/CardHeader.svelte';
|
|
17
|
+
export { default as CardBody } from './components/CardBody.svelte';
|
|
18
|
+
export { default as CardFooter } from './components/CardFooter.svelte';
|
|
19
|
+
export { default as FormField } from './components/FormField.svelte';
|
|
20
|
+
export { default as PhoneInput } from './components/PhoneInput.svelte';
|
|
21
|
+
export { default as DurationInput } from './components/DurationInput.svelte';
|
|
22
|
+
export { default as AutocompleteInput } from './components/AutocompleteInput.svelte';
|
|
23
|
+
export type { AutocompleteSuggestion } from './components/AutocompleteInput.svelte';
|
|
24
|
+
export { default as Badge } from './components/Badge.svelte';
|
|
25
|
+
export { default as Alert } from './components/Alert.svelte';
|
|
26
|
+
export { default as EmptyState } from './components/EmptyState.svelte';
|
|
27
|
+
export type { EmptyStateProps } from './components/EmptyState.svelte';
|
|
28
|
+
export { default as LoadingSpinner } from './components/LoadingSpinner.svelte';
|
|
29
|
+
export { default as Container } from './components/Container.svelte';
|
|
30
|
+
export { default as Row } from './components/Row.svelte';
|
|
31
|
+
export { default as Col } from './components/Col.svelte';
|
|
32
|
+
export { default as Drawer } from './components/Drawer.svelte';
|
|
33
|
+
export { default as Modal } from './components/Modal.svelte';
|
|
34
|
+
export { default as GridView } from './components/GridView.svelte';
|
|
35
|
+
export type { Column, ActionItem } from './components/GridView.types.js';
|
|
36
|
+
export { default as EditableTable } from './components/EditableTable.svelte';
|
|
37
|
+
export type { EditableColumn, EditCellArgs } from './components/EditableTable.svelte';
|
|
38
|
+
export { default as PhotoUpload } from './components/PhotoUpload.svelte';
|
|
39
|
+
export { default as PawPrintIcon } from './icons/PawPrintIcon.svelte';
|
|
40
|
+
export { lockBodyScroll, unlockBodyScroll } from './utils/scrollLock.js';
|
|
41
|
+
export { minutesToHoursAndMinutes, hoursAndMinutesToMinutes } from './utils/duration.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @groundbrick/svelte-ui
|
|
3
|
+
* Reusable Svelte 5 UI components (design system).
|
|
4
|
+
*
|
|
5
|
+
* Import the default theme tokens via `@groundbrick/svelte-ui/styles/tokens.css`
|
|
6
|
+
* and override CSS variables (globally or on a wrapper element) to re-theme.
|
|
7
|
+
*
|
|
8
|
+
* Components assume Bootstrap 5 CSS/JS and Bootstrap Icons are loaded by the
|
|
9
|
+
* consuming app (declared as optional peer dependencies).
|
|
10
|
+
*/
|
|
11
|
+
export const VERSION = '0.1.0';
|
|
12
|
+
// Buttons
|
|
13
|
+
export { default as Button } from './components/Button.svelte';
|
|
14
|
+
export { default as Dropdown } from './components/Dropdown.svelte';
|
|
15
|
+
export { default as DropdownItem } from './components/DropdownItem.svelte';
|
|
16
|
+
// Cards
|
|
17
|
+
export { default as Card } from './components/Card.svelte';
|
|
18
|
+
export { default as CardHeader } from './components/CardHeader.svelte';
|
|
19
|
+
export { default as CardBody } from './components/CardBody.svelte';
|
|
20
|
+
export { default as CardFooter } from './components/CardFooter.svelte';
|
|
21
|
+
// Forms
|
|
22
|
+
export { default as FormField } from './components/FormField.svelte';
|
|
23
|
+
export { default as PhoneInput } from './components/PhoneInput.svelte';
|
|
24
|
+
export { default as DurationInput } from './components/DurationInput.svelte';
|
|
25
|
+
export { default as AutocompleteInput } from './components/AutocompleteInput.svelte';
|
|
26
|
+
// Badges
|
|
27
|
+
export { default as Badge } from './components/Badge.svelte';
|
|
28
|
+
// Alerts
|
|
29
|
+
export { default as Alert } from './components/Alert.svelte';
|
|
30
|
+
// Feedback
|
|
31
|
+
export { default as EmptyState } from './components/EmptyState.svelte';
|
|
32
|
+
export { default as LoadingSpinner } from './components/LoadingSpinner.svelte';
|
|
33
|
+
// Layout
|
|
34
|
+
export { default as Container } from './components/Container.svelte';
|
|
35
|
+
export { default as Row } from './components/Row.svelte';
|
|
36
|
+
export { default as Col } from './components/Col.svelte';
|
|
37
|
+
// Overlays
|
|
38
|
+
export { default as Drawer } from './components/Drawer.svelte';
|
|
39
|
+
export { default as Modal } from './components/Modal.svelte';
|
|
40
|
+
// Tables / data grids
|
|
41
|
+
export { default as GridView } from './components/GridView.svelte';
|
|
42
|
+
export { default as EditableTable } from './components/EditableTable.svelte';
|
|
43
|
+
// Media
|
|
44
|
+
export { default as PhotoUpload } from './components/PhotoUpload.svelte';
|
|
45
|
+
// Icons
|
|
46
|
+
export { default as PawPrintIcon } from './icons/PawPrintIcon.svelte';
|
|
47
|
+
// Utilities
|
|
48
|
+
export { lockBodyScroll, unlockBodyScroll } from './utils/scrollLock.js';
|
|
49
|
+
export { minutesToHoursAndMinutes, hoursAndMinutesToMinutes } from './utils/duration.js';
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
FORMS - @groundbrick/svelte-ui
|
|
3
|
+
Default styling for the `ap-form-*` classes used by FormField,
|
|
4
|
+
DurationInput, PhoneInput and AutocompleteInput. Token-based, so overriding
|
|
5
|
+
CSS variables re-themes the fields. Imported by those components, so it loads
|
|
6
|
+
automatically when any form field is used.
|
|
7
|
+
============================================ */
|
|
8
|
+
|
|
9
|
+
/* ===== FORM FIELD CONTAINER ===== */
|
|
10
|
+
.ap-form-field {
|
|
11
|
+
margin-bottom: var(--spacing-md);
|
|
12
|
+
position: relative;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* ===== LABELS ===== */
|
|
16
|
+
.ap-form-label {
|
|
17
|
+
display: flex;
|
|
18
|
+
align-items: center;
|
|
19
|
+
gap: 0.375rem;
|
|
20
|
+
font-family: var(--font-family-base);
|
|
21
|
+
font-weight: var(--font-weight-medium);
|
|
22
|
+
font-size: var(--font-size-xs);
|
|
23
|
+
color: var(--color-text);
|
|
24
|
+
margin-bottom: 0.375rem;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.ap-form-label-icon {
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
color: var(--color-text-muted);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.ap-form-label-icon svg {
|
|
34
|
+
width: 14px;
|
|
35
|
+
height: 14px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.ap-form-required {
|
|
39
|
+
color: var(--color-danger);
|
|
40
|
+
margin-left: 0.125rem;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* ===== INPUT WRAPPER ===== */
|
|
44
|
+
.ap-form-input-wrapper {
|
|
45
|
+
position: relative;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* ===== FORM CONTROLS ===== */
|
|
49
|
+
.ap-form-control {
|
|
50
|
+
width: 100%;
|
|
51
|
+
padding: 0.72rem 0.92rem;
|
|
52
|
+
font-family: var(--font-family-base);
|
|
53
|
+
font-size: var(--font-size-sm);
|
|
54
|
+
font-weight: var(--font-weight-normal);
|
|
55
|
+
color: var(--color-text);
|
|
56
|
+
background: var(--color-bg-surface);
|
|
57
|
+
border: 1px solid var(--color-border-strong);
|
|
58
|
+
border-radius: var(--radius-lg);
|
|
59
|
+
transition: all var(--transition-base);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.ap-form-control::placeholder {
|
|
63
|
+
color: var(--color-text-subtle);
|
|
64
|
+
font-weight: var(--font-weight-normal);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.ap-form-control:focus {
|
|
68
|
+
outline: none;
|
|
69
|
+
border-color: var(--color-primary);
|
|
70
|
+
box-shadow: 0 0 0 0.25rem var(--focus-ring-color);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.ap-form-control:disabled {
|
|
74
|
+
background-color: var(--color-gray-100);
|
|
75
|
+
cursor: not-allowed;
|
|
76
|
+
opacity: 0.7;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.ap-form-control:read-only {
|
|
80
|
+
background-color: var(--color-gray-50);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* Select specific */
|
|
84
|
+
.ap-form-select {
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
appearance: none;
|
|
87
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%236c757d' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
|
|
88
|
+
background-repeat: no-repeat;
|
|
89
|
+
background-position: right 0.75rem center;
|
|
90
|
+
background-size: 16px 12px;
|
|
91
|
+
padding-right: 2.5rem;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.ap-form-select:disabled {
|
|
95
|
+
cursor: not-allowed;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Textarea specific */
|
|
99
|
+
textarea.ap-form-control {
|
|
100
|
+
resize: vertical;
|
|
101
|
+
min-height: calc(1.5em * 3 + 0.75rem * 2);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Input with icon on left */
|
|
105
|
+
.ap-form-control-with-icon {
|
|
106
|
+
padding-left: 2.5rem;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* ===== INPUT ICON (inside input, left side) ===== */
|
|
110
|
+
.ap-form-input-icon {
|
|
111
|
+
position: absolute;
|
|
112
|
+
left: 0.875rem;
|
|
113
|
+
top: 50%;
|
|
114
|
+
transform: translateY(-50%);
|
|
115
|
+
display: flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
justify-content: center;
|
|
118
|
+
color: var(--color-text-muted);
|
|
119
|
+
pointer-events: none;
|
|
120
|
+
z-index: 1;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.ap-form-input-icon i,
|
|
124
|
+
.ap-form-input-icon svg {
|
|
125
|
+
font-size: 1rem;
|
|
126
|
+
width: 1rem;
|
|
127
|
+
height: 1rem;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* ===== INPUT ADDON (inside input, right side) ===== */
|
|
131
|
+
.ap-form-input-addon {
|
|
132
|
+
position: absolute;
|
|
133
|
+
right: 0.875rem;
|
|
134
|
+
top: 50%;
|
|
135
|
+
transform: translateY(-50%);
|
|
136
|
+
display: flex;
|
|
137
|
+
align-items: center;
|
|
138
|
+
justify-content: center;
|
|
139
|
+
z-index: 1;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* ===== VALIDATION STATES ===== */
|
|
143
|
+
.ap-form-control-invalid {
|
|
144
|
+
border-color: var(--color-danger);
|
|
145
|
+
padding-right: 2.5rem;
|
|
146
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23E4475A'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23E4475A' stroke='none'/%3e%3c/svg%3e");
|
|
147
|
+
background-repeat: no-repeat;
|
|
148
|
+
background-position: right 0.75rem center;
|
|
149
|
+
background-size: 1rem 1rem;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.ap-form-control-invalid:focus {
|
|
153
|
+
border-color: var(--color-danger);
|
|
154
|
+
box-shadow: 0 0 0 0.25rem rgba(228, 71, 90, 0.2);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* ===== HELP/ERROR TEXT ===== */
|
|
158
|
+
.ap-form-error {
|
|
159
|
+
display: flex;
|
|
160
|
+
align-items: center;
|
|
161
|
+
gap: 0.375rem;
|
|
162
|
+
color: var(--color-danger);
|
|
163
|
+
font-size: var(--font-size-xs);
|
|
164
|
+
margin-top: 0.375rem;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.ap-form-error i {
|
|
168
|
+
font-size: 0.875rem;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.ap-form-help {
|
|
172
|
+
display: flex;
|
|
173
|
+
align-items: center;
|
|
174
|
+
gap: 0.375rem;
|
|
175
|
+
color: var(--color-text-muted);
|
|
176
|
+
font-size: var(--font-size-xs);
|
|
177
|
+
margin-top: 0.375rem;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.ap-form-help i {
|
|
181
|
+
font-size: 0.875rem;
|
|
182
|
+
}
|