@donotdev/ui 0.0.15 → 0.0.16
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/components/common/TechBento.d.ts.map +1 -1
- package/dist/components/common/TechBento.js +1 -1
- package/dist/components/layout/components/header/HeaderNavigation.d.ts.map +1 -1
- package/dist/components/layout/components/header/HeaderNavigation.js +2 -2
- package/dist/crud/components/CrudCardLink.d.ts.map +1 -1
- package/dist/crud/components/EntityCardList.d.ts.map +1 -1
- package/dist/crud/components/EntityCardList.js +8 -22
- package/dist/crud/components/EntityList.d.ts.map +1 -1
- package/dist/crud/components/EntityList.js +7 -43
- package/dist/dndev.css +86 -63
- package/dist/index.js +4 -4
- package/dist/internal/devtools/components/DesignTab.d.ts.map +1 -1
- package/dist/internal/layout/components/AutoMetaTags.d.ts.map +1 -1
- package/dist/internal/layout/components/AutoMetaTags.js +2 -9
- package/dist/internal/layout/components/FontPreloadLinks.d.ts.map +1 -1
- package/dist/internal/layout/components/FontPreloadLinks.js +1 -0
- package/dist/internal/layout/components/footer/useLegalLinks.d.ts.map +1 -1
- package/dist/routing/GoToInput.d.ts.map +1 -1
- package/dist/routing/GoToInput.js +2 -1
- package/dist/routing/Link.d.ts.map +1 -1
- package/dist/routing/useRouteDiscovery.d.ts.map +1 -1
- package/dist/styles/index.css +86 -63
- package/dist/utils/sanitizeSvg.d.ts.map +1 -1
- package/dist/utils/useFormStoreSafe.d.ts.map +1 -1
- package/dist/vite-routing/AppRoutes.d.ts.map +1 -1
- package/dist/vite-routing/AppRoutes.js +1 -1
- package/package.json +1 -1
- package/dist/routing/hooks/useFormNavigationBlocker.d.ts +0 -14
- package/dist/routing/hooks/useFormNavigationBlocker.d.ts.map +0 -1
- package/dist/routing/hooks/useFormNavigationBlocker.js +0 -42
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TechBento.d.ts","sourceRoot":"","sources":["../../../src/components/common/TechBento.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TechBento.d.ts","sourceRoot":"","sources":["../../../src/components/common/TechBento.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,cAAc,EACd,IAAI,EACL,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAa,KAAK,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAK/D,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,OAAO,CAAC;QACd,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;QAC3C,OAAO,CAAC,EAAE,WAAW,CAAC;KACvB,CAAC,CAAC;IACH;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC;IAC/B;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,uEAAuE;IACvE,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,yCAAyC;IACzC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0DAA0D;IAC1D,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,0DAA0D;IAC1D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA0CF,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,KAAK,EACL,IAAQ,EACR,OAAO,EACP,GAAc,EACd,SAAiB,EACjB,IAAiB,EACjB,KAAK,EACL,WAAW,EACX,IAAI,EACJ,YAAY,EACZ,WAAW,EACX,SAAS,GACV,EAAE,cAAc,2CA4DhB;AAED,eAAe,SAAS,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// packages/ui/src/components/common/TechBento.tsx
|
|
3
3
|
import { useState } from 'react';
|
|
4
|
-
import { Bento, Card, Section, Stack, Text, TONE, cn } from '@donotdev/components';
|
|
4
|
+
import { Bento, Card, Section, Stack, Text, TONE, cn, } from '@donotdev/components';
|
|
5
5
|
import { techLogos } from '../../data/techLogos';
|
|
6
6
|
import { sanitizeSvg } from '../../utils/sanitizeSvg';
|
|
7
7
|
function TechCard({ techKey, variant, }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HeaderNavigation.d.ts","sourceRoot":"","sources":["../../../../../src/components/layout/components/header/HeaderNavigation.tsx"],"names":[],"mappings":"AAsBA,OAAO,EACL,OAAO,EAIR,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"HeaderNavigation.d.ts","sourceRoot":"","sources":["../../../../../src/components/layout/components/header/HeaderNavigation.tsx"],"names":[],"mappings":"AAsBA,OAAO,EACL,OAAO,EAIR,MAAM,sBAAsB,CAAC;AAa9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,MAAM,WAAW,qBAAqB;IACpC,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC;IACjD;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;GAWG;AACH,QAAA,MAAM,gBAAgB,EAAE,aAAa,CAAC,qBAAqB,CA4E1D,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -24,7 +24,7 @@ import { Link } from '../../../../routing/Link';
|
|
|
24
24
|
import { Icon } from '../../../common/icon';
|
|
25
25
|
import { DnDevNavigationMenu } from '../../../../routing/DnDevNavigationMenu';
|
|
26
26
|
import { NavigationItemComponent } from '../../../../routing/NavigationItem';
|
|
27
|
-
import { useNavigationItems, useNavigationRoute } from '../../../../routing/useNavigation';
|
|
27
|
+
import { useNavigationItems, useNavigationRoute, } from '../../../../routing/useNavigation';
|
|
28
28
|
/**
|
|
29
29
|
* HeaderNavigation - DISPLAY-aware adaptive navigation component
|
|
30
30
|
*
|
|
@@ -47,7 +47,7 @@ const HeaderNavigation = ({ className = '', showIcons = true, display = DISPLAY.
|
|
|
47
47
|
if (path) {
|
|
48
48
|
if (!singleRoute)
|
|
49
49
|
return null;
|
|
50
|
-
return (_jsx(Button, { variant: "ghost", display: display, icon: showIcons ? _jsx(Icon, { icon: singleRoute.icon, fallback: LinkIcon }) : undefined, className: className, render: ({ children, ...props }) => (_jsx(Link, { path: singleRoute.path, ...props, children: children })), children: singleRoute.label }));
|
|
50
|
+
return (_jsx(Button, { variant: "ghost", display: display, icon: showIcons ? (_jsx(Icon, { icon: singleRoute.icon, fallback: LinkIcon })) : undefined, className: className, render: ({ children, ...props }) => (_jsx(Link, { path: singleRoute.path, ...props, children: children })), children: singleRoute.label }));
|
|
51
51
|
}
|
|
52
52
|
const effectiveDisplay = display === DISPLAY.AUTO
|
|
53
53
|
? isMobile || isTablet
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CrudCardLink.d.ts","sourceRoot":"","sources":["../../../src/crud/components/CrudCardLink.tsx"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAIpD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"CrudCardLink.d.ts","sourceRoot":"","sources":["../../../src/crud/components/CrudCardLink.tsx"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAIpD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,aAAa,2CAkBvE;AAED,eAAe,QAAQ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityCardList.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityCardList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"EntityCardList.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityCardList.tsx"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,mBAAmB,EAAgB,MAAM,gBAAgB,CAAC;AAIxE,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,QAAQ,EACR,OAAO,EACP,IAAmB,EACnB,SAA0B,EAAE,2BAA2B;AACvD,MAAM,EACN,WAAmB,EACnB,WAAW,EACX,IAAI,GACL,EAAE,mBAAmB,2CA2LrB"}
|
|
@@ -9,7 +9,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
9
9
|
* **Routing:** Convention basePath = `/${collection}`. View = basePath/:id.
|
|
10
10
|
* Override basePath for nested routes; use onClick(id) to open sheet instead of navigating.
|
|
11
11
|
*
|
|
12
|
-
* @version 0.
|
|
12
|
+
* @version 0.3.0
|
|
13
13
|
* @since 0.0.1
|
|
14
14
|
* @author AMBROISE PARK Consulting
|
|
15
15
|
*/
|
|
@@ -18,7 +18,7 @@ import { Heart } from 'lucide-react';
|
|
|
18
18
|
import { Card, Grid, Stack, Text, Spinner, Section, Button, } from '@donotdev/components';
|
|
19
19
|
import { useTranslation, getListCardFieldNames } from '@donotdev/core';
|
|
20
20
|
import { useNavigate } from '../../routing';
|
|
21
|
-
import { useCrudCardList, EntityFilters, useEntityFavorites,
|
|
21
|
+
import { useCrudCardList, EntityFilters, useEntityFavorites, useCrudFilters, } from '@donotdev/crud';
|
|
22
22
|
import { CrudCard } from './CrudCardLink';
|
|
23
23
|
/**
|
|
24
24
|
* Entity Card List Component - Card grid view for public/user-facing browsing
|
|
@@ -35,33 +35,19 @@ export function EntityCardList({ entity, basePath, onClick, cols = [1, 2, 3, 4],
|
|
|
35
35
|
filter, hideFilters = false, resultLabel, tone, }) {
|
|
36
36
|
const navigate = useNavigate();
|
|
37
37
|
const base = basePath ?? `/${entity.collection}`;
|
|
38
|
-
// useCrudCardList -> handles fetching
|
|
39
|
-
const {
|
|
40
|
-
const rawData = listData?.items || [];
|
|
38
|
+
// useCrudCardList -> handles fetching + client-side filter/search/sort via `processed`
|
|
39
|
+
const { items: rawData, processed, loading, } = useCrudCardList(entity, { staleTime });
|
|
41
40
|
// Favorites - always enabled, no props needed
|
|
42
41
|
const { isFavorite, toggleFavorite, favoritesFilter } = useEntityFavorites({
|
|
43
42
|
collection: entity.collection,
|
|
44
43
|
});
|
|
45
44
|
// Favorites toggle from CrudStore (persists across navigation)
|
|
46
|
-
|
|
47
|
-
const { showFavoritesOnly, setShowFavoritesOnly, filters } = useCrudFilters({
|
|
45
|
+
const { showFavoritesOnly, setShowFavoritesOnly } = useCrudFilters({
|
|
48
46
|
collection: entity.collection,
|
|
49
47
|
});
|
|
50
|
-
// Apply filters
|
|
51
|
-
const applyFilters = useCallback((item) => {
|
|
52
|
-
if (Object.keys(filters).length === 0)
|
|
53
|
-
return true;
|
|
54
|
-
return Object.entries(filters).every(([fieldName, filterValue]) => {
|
|
55
|
-
const itemValue = item[fieldName];
|
|
56
|
-
const fieldConfig = entity.fields[fieldName];
|
|
57
|
-
const fieldType = fieldConfig?.type || 'text';
|
|
58
|
-
return matchesFilter(itemValue, filterValue, fieldType);
|
|
59
|
-
});
|
|
60
|
-
}, [filters, entity.fields]);
|
|
61
|
-
// Apply client-side filtering (including favorites)
|
|
48
|
+
// Apply UI-specific filters (favorites, consumer filter prop) on top of processed
|
|
62
49
|
const data = useMemo(() => {
|
|
63
|
-
let result =
|
|
64
|
-
result = result.filter(applyFilters);
|
|
50
|
+
let result = processed;
|
|
65
51
|
// Apply favorites filter if enabled
|
|
66
52
|
if (showFavoritesOnly) {
|
|
67
53
|
result = result.filter(favoritesFilter);
|
|
@@ -70,7 +56,7 @@ filter, hideFilters = false, resultLabel, tone, }) {
|
|
|
70
56
|
result = result.filter(filter);
|
|
71
57
|
}
|
|
72
58
|
return result;
|
|
73
|
-
}, [
|
|
59
|
+
}, [processed, showFavoritesOnly, favoritesFilter, filter]);
|
|
74
60
|
// Entity + crud namespaces so formatValue can resolve crud:price.* etc.
|
|
75
61
|
const { t } = useTranslation([entity.namespace, 'crud']);
|
|
76
62
|
const { t: tCrud } = useTranslation('crud');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityList.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"EntityList.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityList.tsx"],"names":[],"mappings":"AAwCA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,QAAQ,EACR,OAAO,EACP,WAAmB,EACnB,UAAqB,EACrB,QAAQ,EAAE,YAAY,EACtB,YAAY,EACZ,UAAiB,GAClB,EAAE,eAAe,2CA2QjB"}
|
|
@@ -9,7 +9,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
9
9
|
* **Routing:** Convention basePath = `/${collection}`. View/Edit = basePath/:id, Create = basePath/new.
|
|
10
10
|
* Override basePath for nested routes; use onClick(id) to open sheet instead of navigating.
|
|
11
11
|
*
|
|
12
|
-
* @version 0.
|
|
12
|
+
* @version 0.4.0
|
|
13
13
|
* @since 0.0.1
|
|
14
14
|
* @author AMBROISE PARK Consulting
|
|
15
15
|
*/
|
|
@@ -18,7 +18,7 @@ import { useMemo, useCallback, useState } from 'react';
|
|
|
18
18
|
import { DataTable, Button, Stack, ActionButton, Section, Input, } from '@donotdev/components';
|
|
19
19
|
import { useTranslation } from '@donotdev/core';
|
|
20
20
|
import { useNavigate } from '../../routing';
|
|
21
|
-
import { translateFieldLabel, useCrud, useCrudList, EntityFilters,
|
|
21
|
+
import { translateFieldLabel, useCrud, useCrudList, EntityFilters, formatValue, } from '@donotdev/crud';
|
|
22
22
|
/**
|
|
23
23
|
* Entity List Component - Table view for admin/internal operations
|
|
24
24
|
*
|
|
@@ -37,11 +37,11 @@ export function EntityList({ entity, basePath, onClick, hideFilters = false, pag
|
|
|
37
37
|
// For server-side, we need to track pageSize state (DataTable will call onPageSizeChange)
|
|
38
38
|
// For client-side, we just pass pageSizeProp to DataTable and it handles its own state
|
|
39
39
|
const [serverPageSize, setServerPageSize] = useState(pageSizeProp);
|
|
40
|
-
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
const { data: listData, loading, mutate: refreshList, } = useCrudList(entity, {
|
|
40
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
41
|
+
// useCrudList now handles client-side filter + search + sort via `processed`
|
|
42
|
+
const { data: listData, items: rawData, processed: filteredData, loading, mutate: refreshList, } = useCrudList(entity, {
|
|
44
43
|
pagination,
|
|
44
|
+
searchQuery,
|
|
45
45
|
...(queryOptions && { queryOptions }),
|
|
46
46
|
...(pagination === 'server' && {
|
|
47
47
|
page: currentPage,
|
|
@@ -51,14 +51,8 @@ export function EntityList({ entity, basePath, onClick, hideFilters = false, pag
|
|
|
51
51
|
// useCrud -> handles actions (delete)
|
|
52
52
|
const { delete: deleteItem } = useCrud(entity);
|
|
53
53
|
const { t: tCrud } = useTranslation('crud');
|
|
54
|
-
const data = listData?.items || [];
|
|
55
54
|
// Entity + crud namespaces so formatValue can resolve crud:price.* etc.
|
|
56
55
|
const { t } = useTranslation([entity.namespace, 'crud']);
|
|
57
|
-
// Get filters for applying to data (EntityFilters manages its own state)
|
|
58
|
-
const { filters } = useCrudFilters({
|
|
59
|
-
collection: entity.collection,
|
|
60
|
-
});
|
|
61
|
-
const [searchQuery, setSearchQuery] = useState('');
|
|
62
56
|
// Refresh handler - triggers manual refetch in useList
|
|
63
57
|
const handleRefresh = useCallback(async () => {
|
|
64
58
|
await refreshList();
|
|
@@ -84,36 +78,6 @@ export function EntityList({ entity, basePath, onClick, hideFilters = false, pag
|
|
|
84
78
|
const handleDelete = useCallback(async (itemId) => {
|
|
85
79
|
await deleteItem(itemId);
|
|
86
80
|
}, [deleteItem]);
|
|
87
|
-
// Apply search and filters to data
|
|
88
|
-
// @todo Server-side filtering: Currently only handles client-side filtering.
|
|
89
|
-
// When pagination='server', filters should be sent to the server via useCrudList options.
|
|
90
|
-
// Until then, filters are applied client-side after fetching.
|
|
91
|
-
const filteredData = useMemo(() => {
|
|
92
|
-
let result = data;
|
|
93
|
-
// Apply search query (searches all fields)
|
|
94
|
-
if (searchQuery) {
|
|
95
|
-
const searchLower = searchQuery.toLowerCase();
|
|
96
|
-
result = result.filter((item) => {
|
|
97
|
-
return Object.values(item).some((value) => {
|
|
98
|
-
if (value === null || value === undefined)
|
|
99
|
-
return false;
|
|
100
|
-
return String(value).toLowerCase().includes(searchLower);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
// Apply column filters
|
|
105
|
-
if (Object.keys(filters).length > 0) {
|
|
106
|
-
result = result.filter((item) => {
|
|
107
|
-
return Object.entries(filters).every(([fieldName, filterValue]) => {
|
|
108
|
-
const itemValue = item[fieldName];
|
|
109
|
-
const fieldConfig = entity.fields[fieldName];
|
|
110
|
-
const fieldType = fieldConfig?.type || 'text';
|
|
111
|
-
return matchesFilter(itemValue, filterValue, fieldType);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
return result;
|
|
116
|
-
}, [data, searchQuery, filters, entity.fields]);
|
|
117
81
|
// Generate columns from entity.listFields or entity.fields
|
|
118
82
|
const columns = useMemo(() => {
|
|
119
83
|
const fieldsToShow = entity.listFields || Object.keys(entity.fields);
|
|
@@ -170,7 +134,7 @@ export function EntityList({ entity, basePath, onClick, hideFilters = false, pag
|
|
|
170
134
|
defaultValue: `Browse ${entityName} - Filters`,
|
|
171
135
|
}), collapsible: true, defaultOpen: true, children: _jsxs(Stack, { children: [_jsxs(Stack, { direction: "row", gap: "tight", align: "center", className: "dndev-w-full", style: { display: 'grid', gridTemplateColumns: '1fr auto auto' }, children: [_jsx(Input, { placeholder: tCrud('search.placeholder', {
|
|
172
136
|
defaultValue: 'Search...',
|
|
173
|
-
}), value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), icon: Search, className: "dndev-w-full" }), _jsx(Button, { icon: RefreshCw, variant: "outline", onClick: handleRefresh, disabled: loading, display: "compact", "aria-label": tCrud('refresh', { defaultValue: 'Refresh' }) }), _jsx(Button, { icon: Plus, onClick: handleCreate, display: "compact", children: tCrud('addNew', { defaultValue: 'Add New' }) })] }), !hideFilters && (_jsx(EntityFilters, { entity: entity, data:
|
|
137
|
+
}), value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), icon: Search, className: "dndev-w-full" }), _jsx(Button, { icon: RefreshCw, variant: "outline", onClick: handleRefresh, disabled: loading, display: "compact", "aria-label": tCrud('refresh', { defaultValue: 'Refresh' }) }), _jsx(Button, { icon: Plus, onClick: handleCreate, display: "compact", children: tCrud('addNew', { defaultValue: 'Add New' }) })] }), !hideFilters && (_jsx(EntityFilters, { entity: entity, data: rawData, fieldsToFilter: entity.listFields }))] }) }), _jsx(Section, { title: loading
|
|
174
138
|
? tCrud('results.title.fetching', {
|
|
175
139
|
defaultValue: 'Fetching...',
|
|
176
140
|
})
|
package/dist/dndev.css
CHANGED
|
@@ -3422,80 +3422,120 @@ em {
|
|
|
3422
3422
|
|
|
3423
3423
|
/* packages/components/src/atomic/Combobox/Combobox.css */
|
|
3424
3424
|
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
align-items: center;
|
|
3429
|
-
width: 100%;
|
|
3430
|
-
text-align: start;
|
|
3431
|
-
}
|
|
3425
|
+
/* ──────────────────────────────────────────────────
|
|
3426
|
+
Trailing icon group — flex row inside the input area
|
|
3427
|
+
────────────────────────────────────────────────── */
|
|
3432
3428
|
|
|
3433
|
-
.dndev-combobox-
|
|
3429
|
+
.dndev-combobox-trailing {
|
|
3430
|
+
position: absolute;
|
|
3431
|
+
inset-inline-end: var(--gap-sm);
|
|
3432
|
+
top: 0;
|
|
3433
|
+
height: 100%;
|
|
3434
3434
|
display: flex;
|
|
3435
|
-
justify-content: space-between;
|
|
3436
3435
|
align-items: center;
|
|
3437
|
-
|
|
3436
|
+
gap: var(--gap-tight, 4px);
|
|
3437
|
+
z-index: 1;
|
|
3438
|
+
pointer-events: none; /* pass clicks through to input by default */
|
|
3438
3439
|
}
|
|
3439
3440
|
|
|
3440
|
-
.
|
|
3441
|
-
|
|
3442
|
-
}
|
|
3441
|
+
/* Input padding: reserve space for trailing content.
|
|
3442
|
+
--combobox-pad-end is set as an inline CSS variable on .dndev-combobox-wrapper. */
|
|
3443
3443
|
|
|
3444
|
-
.dndev-combobox-
|
|
3445
|
-
|
|
3446
|
-
align-items: center;
|
|
3447
|
-
gap: var(--gap-tight);
|
|
3448
|
-
margin-inline-start: auto;
|
|
3444
|
+
.dndev-combobox-wrapper .dndev-input {
|
|
3445
|
+
padding-inline-end: var(--combobox-pad-end);
|
|
3449
3446
|
}
|
|
3450
3447
|
|
|
3451
|
-
|
|
3448
|
+
/* Action buttons (create "+", clear "X") */
|
|
3449
|
+
|
|
3450
|
+
.dndev-combobox-action-btn {
|
|
3451
|
+
all: unset;
|
|
3452
3452
|
display: flex;
|
|
3453
3453
|
align-items: center;
|
|
3454
3454
|
justify-content: center;
|
|
3455
|
+
width: var(--icon-md);
|
|
3456
|
+
height: var(--icon-md);
|
|
3457
|
+
border-radius: var(--radius-interactive, var(--radius-sm, 4px));
|
|
3455
3458
|
cursor: pointer;
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3459
|
+
pointer-events: auto; /* re-enable clicks on buttons */
|
|
3460
|
+
color: var(--muted-foreground);
|
|
3461
|
+
opacity: var(--opacity-muted, 0.5);
|
|
3462
|
+
transition:
|
|
3463
|
+
opacity var(--dur-fast) var(--ease-in-out),
|
|
3464
|
+
background-color var(--dur-fast) var(--ease-in-out);
|
|
3461
3465
|
}
|
|
3462
3466
|
|
|
3463
|
-
.dndev-combobox-
|
|
3464
|
-
|
|
3467
|
+
.dndev-combobox-action-btn:hover {
|
|
3468
|
+
opacity: 1;
|
|
3469
|
+
background-color: var(--accent, rgba(0, 0, 0, 0.06));
|
|
3470
|
+
}
|
|
3471
|
+
|
|
3472
|
+
.dndev-combobox-action-btn:focus-visible {
|
|
3465
3473
|
opacity: 1;
|
|
3466
3474
|
outline: none;
|
|
3475
|
+
box-shadow:
|
|
3476
|
+
0 0 0 2px var(--ring),
|
|
3477
|
+
0 0 0 4px rgb(from var(--ring) r g b / 0.2);
|
|
3467
3478
|
}
|
|
3468
3479
|
|
|
3469
|
-
.dndev-combobox-
|
|
3470
|
-
|
|
3471
|
-
|
|
3480
|
+
.dndev-combobox-action-btn:active {
|
|
3481
|
+
opacity: 0.8;
|
|
3482
|
+
}
|
|
3483
|
+
|
|
3484
|
+
.dndev-combobox-action-btn svg {
|
|
3485
|
+
width: var(--size-icon-sm, 16px);
|
|
3486
|
+
height: var(--size-icon-sm, 16px);
|
|
3487
|
+
}
|
|
3488
|
+
|
|
3489
|
+
/* Create button accent color */
|
|
3490
|
+
|
|
3491
|
+
.dndev-combobox-action-btn--create {
|
|
3492
|
+
color: var(--primary);
|
|
3493
|
+
}
|
|
3494
|
+
|
|
3495
|
+
/* Clear button */
|
|
3496
|
+
|
|
3497
|
+
.dndev-combobox-action-btn--clear {
|
|
3498
|
+
color: var(--muted-foreground);
|
|
3472
3499
|
}
|
|
3473
3500
|
|
|
3501
|
+
/* Chevron indicator (non-interactive, just visual) */
|
|
3502
|
+
|
|
3474
3503
|
.dndev-combobox-chevron {
|
|
3475
3504
|
width: var(--icon-md);
|
|
3476
3505
|
height: var(--icon-md);
|
|
3506
|
+
display: flex;
|
|
3507
|
+
align-items: center;
|
|
3508
|
+
justify-content: center;
|
|
3509
|
+
color: var(--muted-foreground);
|
|
3477
3510
|
opacity: var(--opacity-muted);
|
|
3511
|
+
pointer-events: none;
|
|
3512
|
+
}
|
|
3513
|
+
|
|
3514
|
+
.dndev-combobox-chevron svg {
|
|
3515
|
+
width: var(--icon-md);
|
|
3516
|
+
height: var(--icon-md);
|
|
3478
3517
|
transition: transform var(--dur-fast) var(--ease-in-out);
|
|
3479
3518
|
}
|
|
3480
3519
|
|
|
3481
|
-
|
|
3520
|
+
.dndev-combobox-open .dndev-combobox-chevron svg {
|
|
3482
3521
|
transform: rotate(180deg);
|
|
3483
3522
|
}
|
|
3484
3523
|
|
|
3485
|
-
|
|
3524
|
+
/* Spinner replaces chevron */
|
|
3525
|
+
|
|
3526
|
+
.dndev-combobox-spinner {
|
|
3486
3527
|
display: flex;
|
|
3487
3528
|
align-items: center;
|
|
3488
|
-
|
|
3489
|
-
}
|
|
3490
|
-
|
|
3491
|
-
.dndev-combobox-loading-spinner {
|
|
3529
|
+
justify-content: center;
|
|
3492
3530
|
width: var(--icon-md);
|
|
3493
3531
|
height: var(--icon-md);
|
|
3494
|
-
|
|
3495
|
-
border: 2px solid currentColor;
|
|
3496
|
-
border-top-color: transparent;
|
|
3532
|
+
pointer-events: none;
|
|
3497
3533
|
}
|
|
3498
3534
|
|
|
3535
|
+
/* ──────────────────────────────────────────────────
|
|
3536
|
+
Dropdown content
|
|
3537
|
+
────────────────────────────────────────────────── */
|
|
3538
|
+
|
|
3499
3539
|
.dndev-combobox-content {
|
|
3500
3540
|
width: var(--radix-popover-trigger-width);
|
|
3501
3541
|
min-width: var(--radix-popover-trigger-width);
|
|
@@ -3505,15 +3545,6 @@ em {
|
|
|
3505
3545
|
padding: 0;
|
|
3506
3546
|
}
|
|
3507
3547
|
|
|
3508
|
-
.dndev-combobox-search-container {
|
|
3509
|
-
padding: var(--gap-sm);
|
|
3510
|
-
border-bottom: var(--border-width) solid var(--line-2);
|
|
3511
|
-
}
|
|
3512
|
-
|
|
3513
|
-
.dndev-combobox-search-input {
|
|
3514
|
-
width: 100%;
|
|
3515
|
-
}
|
|
3516
|
-
|
|
3517
3548
|
.dndev-combobox-option {
|
|
3518
3549
|
all: unset;
|
|
3519
3550
|
display: flex;
|
|
@@ -3584,20 +3615,6 @@ em {
|
|
|
3584
3615
|
flex-shrink: 0;
|
|
3585
3616
|
}
|
|
3586
3617
|
|
|
3587
|
-
.dndev-combobox-create-btn:hover {
|
|
3588
|
-
opacity: 0.8;
|
|
3589
|
-
}
|
|
3590
|
-
|
|
3591
|
-
.dndev-combobox-open .dndev-input-with-trailing-icon .dndev-input-icon svg,
|
|
3592
|
-
.dndev-combobox-open .dndev-input-with-trailing-icon .dndev-input-icon > * {
|
|
3593
|
-
transform: rotate(180deg);
|
|
3594
|
-
}
|
|
3595
|
-
|
|
3596
|
-
.dndev-input-with-trailing-icon .dndev-input-icon svg,
|
|
3597
|
-
.dndev-input-with-trailing-icon .dndev-input-icon > * {
|
|
3598
|
-
transition: transform var(--dur-fast) var(--ease-in-out);
|
|
3599
|
-
}
|
|
3600
|
-
|
|
3601
3618
|
/* packages/components/src/atomic/DualCard/DualCard.css */
|
|
3602
3619
|
|
|
3603
3620
|
.dndev-dual-card {
|
|
@@ -9498,7 +9515,10 @@ main[role='main'][data-routing-animation='none'] {
|
|
|
9498
9515
|
max-height: none;
|
|
9499
9516
|
overflow-y: visible;
|
|
9500
9517
|
overflow-x: hidden;
|
|
9501
|
-
grid-template-rows: var(--header-height) minmax(
|
|
9518
|
+
grid-template-rows: var(--header-height) minmax(
|
|
9519
|
+
calc(100dvh - var(--header-height)),
|
|
9520
|
+
auto
|
|
9521
|
+
) auto;
|
|
9502
9522
|
}
|
|
9503
9523
|
|
|
9504
9524
|
.dndev-layout[data-footer-mode='scroll'] header[role='banner'] {
|
|
@@ -9539,7 +9559,10 @@ main[role='main'][data-routing-animation='none'] {
|
|
|
9539
9559
|
max-height: none;
|
|
9540
9560
|
overflow-y: visible;
|
|
9541
9561
|
overflow-x: hidden;
|
|
9542
|
-
grid-template-rows: var(--header-height) minmax(
|
|
9562
|
+
grid-template-rows: var(--header-height) minmax(
|
|
9563
|
+
calc(100dvh - var(--header-height)),
|
|
9564
|
+
auto
|
|
9565
|
+
) auto;
|
|
9543
9566
|
}
|
|
9544
9567
|
|
|
9545
9568
|
.dndev-layout header[role='banner'] {
|