@jini-ai/ui 0.4.6 → 0.4.8
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 +33 -0
- package/dist/features/admin-widgets/components/InfoTip.d.ts +23 -2
- package/dist/features/admin-widgets/components/InfoTip.hooks.d.ts +22 -2
- package/dist/features/admin-widgets/components/InfoTip.hooks.js +75 -28
- package/dist/features/admin-widgets/components/InfoTip.js +12 -4
- package/dist/features/admin-widgets/components/InfoTip.rules.d.ts +72 -0
- package/dist/features/admin-widgets/components/InfoTip.rules.js +68 -0
- package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.d.ts +36 -0
- package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.d.ts +58 -0
- package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.js +66 -0
- package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.js +24 -0
- package/dist/features/admin-widgets/components/useDebouncedHtmlPreview.hooks.d.ts +23 -0
- package/dist/features/admin-widgets/components/useDebouncedHtmlPreview.hooks.js +28 -0
- package/dist/features/admin-widgets/index.d.ts +9 -0
- package/dist/features/admin-widgets/index.js +5 -0
- package/dist/features/execution/constants.js +11 -10
- package/dist/features/execution/http-adapter.d.ts +3 -1
- package/dist/features/execution/http-adapter.js +9 -4
- package/dist/features/execution/index.d.ts +1 -1
- package/dist/features/execution/index.js +1 -1
- package/dist/features/execution/react/components/ByokProviderForm.d.ts +18 -1
- package/dist/features/execution/react/components/ByokProviderForm.js +14 -16
- package/dist/features/execution/react/components/LocalCliAgentCard.d.ts +5 -1
- package/dist/features/execution/react/components/LocalCliAgentCard.js +12 -87
- package/dist/features/execution/react/components/LocalCliAgentList.d.ts +4 -1
- package/dist/features/execution/react/components/LocalCliAgentList.js +13 -4
- package/dist/features/execution/react/components/LocalCliAgentSettings.d.ts +20 -0
- package/dist/features/execution/react/components/LocalCliAgentSettings.js +20 -0
- package/dist/features/execution/react/hooks/use-byok-field-validation.hooks.d.ts +24 -0
- package/dist/features/execution/react/hooks/use-byok-field-validation.hooks.js +27 -0
- package/dist/features/execution/react/hooks/useExecutionTab.js +10 -1
- package/dist/features/execution/react/hooks/useLocalCliAgentCard.d.ts +48 -0
- package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +110 -0
- package/dist/features/execution/react/hooks/useLocalCliAgentList.d.ts +19 -0
- package/dist/features/execution/react/hooks/useLocalCliAgentList.js +13 -0
- package/dist/features/execution/rules.d.ts +13 -0
- package/dist/features/execution/rules.js +14 -0
- package/dist/features/execution/types.d.ts +2 -0
- package/dist/features/html-editor/canvas-embed-placeholders.d.ts +13 -1
- package/dist/features/html-editor/canvas-embed-placeholders.js +61 -12
- package/dist/features/html-editor/dom.d.ts +5 -0
- package/dist/features/html-editor/dom.js +10 -0
- package/dist/features/html-editor/editor-blocks.d.ts +71 -0
- package/dist/features/html-editor/editor-blocks.js +185 -0
- package/dist/features/html-editor/editor-serialization.d.ts +24 -0
- package/dist/features/html-editor/editor-serialization.js +110 -0
- package/dist/features/html-editor/index.d.ts +5 -0
- package/dist/features/html-editor/index.js +3 -0
- package/dist/features/html-editor/protected-elements.d.ts +64 -0
- package/dist/features/html-editor/protected-elements.js +189 -0
- package/dist/features/html-editor/react/components/InteractiveHtmlEditor.d.ts +6 -4
- package/dist/features/html-editor/react/components/InteractiveHtmlEditor.js +3 -3
- package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.d.ts +9 -1
- package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +107 -196
- package/dist/features/html-editor/source-splice.d.ts +23 -0
- package/dist/features/html-editor/source-splice.js +45 -0
- package/dist/features/i18n/dictionaries/settings-dialog.ar.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.bn.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.de.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.en.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.es.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.fa.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.fr.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.hi.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.hu.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.id.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.it.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.ja.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.ko.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.pl.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.pt-BR.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.ru.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.th.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.tr.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.uk.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.ur.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +4 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +4 -0
- package/dist/features/interactive-ui/interactive-ui.css +1 -1
- package/dist/features/interactive-ui/providers/native/data-table.js +8 -1
- package/dist/features/interactive-ui/providers/native/data-table.manifest.d.ts +3 -5
- package/dist/features/interactive-ui/providers/native/data-table.manifest.js +5 -7
- package/dist/features/interactive-ui/providers/recharts/bar-chart.js +8 -3
- package/dist/features/interactive-ui/providers/recharts/chart-config.d.ts +40 -0
- package/dist/features/interactive-ui/providers/recharts/chart-config.js +32 -0
- package/dist/features/interactive-ui/providers/recharts/chart-tokens.d.ts +18 -12
- package/dist/features/interactive-ui/providers/recharts/chart-tokens.js +6 -11
- package/dist/features/interactive-ui/providers/recharts/chart.d.ts +31 -0
- package/dist/features/interactive-ui/providers/recharts/chart.js +34 -0
- package/dist/features/interactive-ui/providers/recharts/line-chart.js +10 -3
- package/dist/features/interactive-ui/providers/recharts/pie-chart.js +8 -3
- package/dist/features/interactive-ui/providers/shadcn/button.d.ts +1 -1
- package/dist/features/interactive-ui/providers/shadcn/data-table.d.ts +5 -1
- package/dist/features/interactive-ui/providers/shadcn/data-table.js +26 -2
- package/dist/features/interactive-ui/providers/shadcn/data-table.manifest.d.ts +8 -1
- package/dist/features/interactive-ui/providers/shadcn/data-table.manifest.js +6 -3
- package/dist/features/interactive-ui/table-data.d.ts +25 -0
- package/dist/features/interactive-ui/table-data.js +36 -0
- package/dist/features/mcp-ui/escape.js +2 -6
- package/dist/features/mcp-ui/sandbox-proxy-link-forwarder.d.ts +26 -0
- package/dist/features/mcp-ui/sandbox-proxy-link-forwarder.js +40 -0
- package/dist/features/mcp-ui/sandbox-proxy.d.ts +5 -1
- package/dist/features/mcp-ui/sandbox-proxy.js +11 -0
- package/dist/features/mcp-ui/surfaces/bridge.js +9 -3
- package/dist/features/mcp-ui/surfaces/document.d.ts +11 -4
- package/dist/features/mcp-ui/surfaces/document.js +25 -3
- package/dist/features/mcp-ui/surfaces/outcome.js +1 -1
- package/dist/features/media-providers/constants.d.ts +0 -7
- package/dist/features/media-providers/constants.js +7 -15
- package/dist/features/media-providers/react/components/MediaProvidersTab.js +3 -2
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +6 -3
- package/dist/features/memory/dependencies.d.ts +2 -0
- package/dist/features/memory/dependencies.js +9 -25
- package/dist/features/memory/index.d.ts +1 -0
- package/dist/features/memory/index.js +1 -0
- package/dist/features/memory/react/MemoryPorts.d.ts +17 -0
- package/dist/features/memory/react/MemoryPorts.js +15 -0
- package/dist/features/memory/react/hooks/useMemoryConfig.hooks.d.ts +2 -2
- package/dist/features/memory/react/hooks/useMemoryConfig.hooks.js +7 -7
- package/dist/features/memory/react/hooks/useMemoryConnectors.hooks.d.ts +2 -3
- package/dist/features/memory/react/hooks/useMemoryConnectors.hooks.js +4 -5
- package/dist/features/memory/react/hooks/useMemoryEntries.hooks.d.ts +2 -3
- package/dist/features/memory/react/hooks/useMemoryEntries.hooks.js +4 -5
- package/dist/features/memory/react/hooks/useMemoryExtractions.hooks.js +2 -2
- package/dist/features/panel-kit/fetch-query/adapter.react.d.ts +2 -2
- package/dist/features/panel-kit/fetch-query/adapter.react.js +5 -3
- package/dist/features/panel-kit/fetch-query/adapter.tanstack.d.ts +11 -0
- package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +212 -0
- package/dist/features/panel-kit/fetch-query/binding.react.d.ts +17 -0
- package/dist/features/panel-kit/fetch-query/binding.react.js +24 -0
- package/dist/features/panel-kit/fetch-query/environment.browser.d.ts +1 -1
- package/dist/features/panel-kit/fetch-query/index.d.ts +6 -3
- package/dist/features/panel-kit/fetch-query/index.js +2 -1
- package/dist/features/panel-kit/fetch-query/tanstack.d.ts +8 -0
- package/dist/features/panel-kit/fetch-query/tanstack.js +4 -0
- package/dist/features/panel-kit/helpers/standing-draft-recovery-message.d.ts +3 -1
- package/dist/features/panel-kit/helpers/standing-draft-recovery-message.js +9 -2
- package/dist/features/settings/dialog/styles/settings-dialog.css +169 -21
- package/dist/features/tabbed-dialog/styles/tabbed-dialog.css +91 -0
- package/dist/react/components/RemixIcon.d.ts +1 -41
- package/dist/react/components/RemixIcon.js +3 -176
- package/dist/react/components/RemixIcon.stylesheet.d.ts +84 -0
- package/dist/react/components/RemixIcon.stylesheet.js +208 -0
- package/dist/react/components/remixicon-font-recovery.d.ts +55 -0
- package/dist/react/components/remixicon-font-recovery.js +110 -0
- package/dist/styles/admin.css +8 -2
- package/package.json +25 -8
- package/dist/features/panel-kit/fetch-query/cache.d.ts +0 -123
- package/dist/features/panel-kit/fetch-query/cache.js +0 -231
- package/dist/features/panel-kit/fetch-query/types.d.ts +0 -91
- package/dist/features/panel-kit/fetch-query/types.js +0 -2
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/** Optional TanStack translation layer. No library types escape the fetch-query contract. */
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useSyncExternalStore } from 'react';
|
|
4
|
+
import { isCancelledError, QueryClient, QueryClientProvider, useMutation, useQuery } from '@tanstack/react-query';
|
|
5
|
+
import { DEFAULT_STALE_TIME, FetchQueryCache, IDLE_RETENTION, toQueryError } from '@jini-ai/core/fetch';
|
|
6
|
+
import { browserFetchQueryEnvironment } from './environment.browser.js';
|
|
7
|
+
import { resolveFetchQueryError, resolveFetchQueryStatus } from './adapter.react.js';
|
|
8
|
+
import { FetchQueryBinding } from './binding.react.js';
|
|
9
|
+
const ScopeContext = createContext(null);
|
|
10
|
+
/** Match built-in defaults. Failed authorization/validation must surface immediately;
|
|
11
|
+
* automatic retries would hide the server's first useful error behind repeated requests. */
|
|
12
|
+
function createScope({ environment }) {
|
|
13
|
+
return {
|
|
14
|
+
client: new QueryClient({ defaultOptions: {
|
|
15
|
+
queries: { staleTime: DEFAULT_STALE_TIME, retry: false, refetchOnWindowFocus: false, refetchOnReconnect: false, networkMode: 'always' },
|
|
16
|
+
mutations: { retry: false, networkMode: 'always' },
|
|
17
|
+
} }),
|
|
18
|
+
// Reuse the existing connectivity gate; TanStack's online/focus managers are global
|
|
19
|
+
// and cannot represent two providers with independent host environment ports.
|
|
20
|
+
gate: new FetchQueryCache({}, { environment }), environment, history: new WeakMap(),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** Provider-owned TanStack cache and binding, compatible with hooks from the default entry.
|
|
24
|
+
* @example <FetchQueryProvider><ResourceScreen /></FetchQueryProvider>
|
|
25
|
+
* @param props Children and optional host connectivity/focus port. */
|
|
26
|
+
export function FetchQueryProvider({ children, environment = browserFetchQueryEnvironment }) {
|
|
27
|
+
// A module singleton would leak cache values between independent providers/tests,
|
|
28
|
+
// producing cases that pass alone but fail together. Scope ownership to this provider.
|
|
29
|
+
const scope = useMemo(() => createScope({ environment }), [environment]);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
scope.gate.activate();
|
|
32
|
+
let online = environment.isOnline();
|
|
33
|
+
const release = environment.subscribeOnline({ listener: next => {
|
|
34
|
+
const reconnect = next && !online;
|
|
35
|
+
online = next;
|
|
36
|
+
// An offline/online pair may be batched into one React render. Signal the cache
|
|
37
|
+
// directly rather than depending on a disabled -> enabled render to revalidate.
|
|
38
|
+
if (reconnect)
|
|
39
|
+
void scope.client.refetchQueries({ predicate: query => query.isActive() && query.isStale() && query.state.fetchStatus !== 'fetching' });
|
|
40
|
+
} });
|
|
41
|
+
return () => { release(); scope.gate.dispose(); };
|
|
42
|
+
}, [scope, environment]);
|
|
43
|
+
return _jsx(QueryClientProvider, { client: scope.client, children: _jsx(ScopeContext.Provider, { value: scope, children: _jsx(FetchQueryBinding, { adapter: adapter, children: children }) }) });
|
|
44
|
+
}
|
|
45
|
+
/** Fail closed when an adapter hook is used without its provider. */
|
|
46
|
+
function useScope() {
|
|
47
|
+
const scope = useContext(ScopeContext);
|
|
48
|
+
if (!scope)
|
|
49
|
+
throw new Error('Fetch-query hooks require FetchQueryProvider');
|
|
50
|
+
return scope;
|
|
51
|
+
}
|
|
52
|
+
/** Observe only this provider's connectivity; paused reads do not claim network activity. */
|
|
53
|
+
function useOnline({ environment }) {
|
|
54
|
+
const subscribe = useCallback((listener) => environment.subscribeOnline({ listener }), [environment]);
|
|
55
|
+
const snapshot = useCallback(() => environment.isOnline(), [environment]);
|
|
56
|
+
return useSyncExternalStore(subscribe, snapshot, snapshot);
|
|
57
|
+
}
|
|
58
|
+
/** Preserve contract metadata across observers, without retaining evicted query objects. */
|
|
59
|
+
function historyFor({ scope, query }) {
|
|
60
|
+
let history = scope.history.get(query);
|
|
61
|
+
if (!history) {
|
|
62
|
+
history = { replacement: 0, request: 0, error: null };
|
|
63
|
+
scope.history.set(query, history);
|
|
64
|
+
}
|
|
65
|
+
return history;
|
|
66
|
+
}
|
|
67
|
+
/** Replacement writes win over either outcome of an older transport, across all loaders
|
|
68
|
+
* and reactive reads. Weak keys follow TanStack's own query eviction lifecycle. */
|
|
69
|
+
async function read({ scope, key, fetch }) {
|
|
70
|
+
const query = scope.client.getQueryCache().find({ queryKey: key, exact: true });
|
|
71
|
+
const history = historyFor({ scope, query });
|
|
72
|
+
const generation = history.replacement;
|
|
73
|
+
const request = ++history.request;
|
|
74
|
+
try {
|
|
75
|
+
const value = await scope.gate.runOnline({ run: fetch });
|
|
76
|
+
if (generation !== history.replacement)
|
|
77
|
+
return scope.client.getQueryData(key);
|
|
78
|
+
if (value === undefined)
|
|
79
|
+
throw new Error(`${JSON.stringify(key)} data is undefined`);
|
|
80
|
+
if (request === history.request)
|
|
81
|
+
history.error = null;
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (generation !== history.replacement)
|
|
86
|
+
return scope.client.getQueryData(key);
|
|
87
|
+
// Earlier data remains useful, but a failed refresh is not a fresh cache hit.
|
|
88
|
+
// The next loader/mount must retry even when its staleTime would retain that data.
|
|
89
|
+
if (request === history.request) {
|
|
90
|
+
history.error = toQueryError(error);
|
|
91
|
+
query.invalidate();
|
|
92
|
+
}
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** Match the built-in cache's idle retention. TanStack's default gcTime (5 min) would
|
|
97
|
+
* otherwise evict an unobserved entry before a longer staleTime says it is stale. */
|
|
98
|
+
function gcTimeFor({ staleTime }) {
|
|
99
|
+
return Math.max(IDLE_RETENTION, staleTime);
|
|
100
|
+
}
|
|
101
|
+
/** Reactive read translated to the library-free contract, with explicit focus opt-in. */
|
|
102
|
+
function useFetchQuery({ key, fetch }, { enabled = true, staleTime = DEFAULT_STALE_TIME, refetchOnWindowFocus = false } = {}) {
|
|
103
|
+
const scope = useScope();
|
|
104
|
+
const online = useOnline(scope);
|
|
105
|
+
const query = useQuery({ queryKey: key, queryFn: () => read({ scope, key, fetch }), enabled: enabled && online, staleTime, gcTime: gcTimeFor({ staleTime }) }, scope.client);
|
|
106
|
+
const { refetch: refresh } = query;
|
|
107
|
+
const refetch = useCallback(() => {
|
|
108
|
+
if (scope.environment.isOnline()) {
|
|
109
|
+
supersedeInitialRead({ scope, key });
|
|
110
|
+
void refresh();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
// Reconnect may already have started a fetch (re-enabled observer or provider refetch);
|
|
114
|
+
// that request postdates this one, so join it instead of cancelling it into a duplicate.
|
|
115
|
+
void scope.gate.runOnline({ run: () => refresh({ cancelRefetch: false }) });
|
|
116
|
+
}, [scope, refresh, JSON.stringify(key)]);
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
if (!enabled || !refetchOnWindowFocus)
|
|
119
|
+
return;
|
|
120
|
+
return scope.environment.subscribeFocus({ listener: () => {
|
|
121
|
+
const cached = scope.client.getQueryCache().find({ queryKey: key, exact: true });
|
|
122
|
+
if (scope.environment.isOnline() && cached?.isStaleByTime(staleTime) && cached.state.fetchStatus !== 'fetching')
|
|
123
|
+
refetch();
|
|
124
|
+
} });
|
|
125
|
+
}, [scope, JSON.stringify(key), enabled, staleTime, refetchOnWindowFocus, refetch]);
|
|
126
|
+
// TanStack clears an initial error when a retry starts. The contract keeps it until
|
|
127
|
+
// recovery, so a retry is never mistaken for evidence that the last failure is gone.
|
|
128
|
+
const cached = scope.client.getQueryCache().find({ queryKey: key, exact: true });
|
|
129
|
+
const history = historyFor({ scope, query: cached });
|
|
130
|
+
const hasData = query.data !== undefined;
|
|
131
|
+
return {
|
|
132
|
+
data: query.data,
|
|
133
|
+
status: resolveFetchQueryStatus({ disabled: !enabled, hasData, status: query.status }),
|
|
134
|
+
error: resolveFetchQueryError({ error: history.error ?? query.error, disabled: !enabled, hasData }),
|
|
135
|
+
isFetching: online && query.isFetching, refetch,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/** Preserve promise rejection for awaiting writes while also handling discarded promises. */
|
|
139
|
+
function useFetchMutation({ run }, { invalidates } = {}) {
|
|
140
|
+
const scope = useScope();
|
|
141
|
+
const mutation = useMutation({
|
|
142
|
+
mutationFn: required => scope.gate.runOnline({ run: () => run(required) }),
|
|
143
|
+
onSuccess: () => {
|
|
144
|
+
// Do not await dependent reads: the mutation promise means the write succeeded,
|
|
145
|
+
// not that every list finished reloading. Refetches proceed on their own schedule.
|
|
146
|
+
for (const key of invalidates ?? [])
|
|
147
|
+
invalidateResource({ scope, key });
|
|
148
|
+
},
|
|
149
|
+
}, scope.client);
|
|
150
|
+
const { mutateAsync, reset } = mutation;
|
|
151
|
+
const mutate = useCallback((required) => {
|
|
152
|
+
const promise = mutateAsync(required);
|
|
153
|
+
// Handle this same promise for callers that discard it, while still returning it so
|
|
154
|
+
// await/catch observes the original rejection; discarding the derived promise is intentional.
|
|
155
|
+
void promise.catch(() => { });
|
|
156
|
+
return promise;
|
|
157
|
+
}, [mutateAsync]);
|
|
158
|
+
return { mutate, status: mutation.status, error: mutation.status === 'error' ? toQueryError(mutation.error) : null, reset };
|
|
159
|
+
}
|
|
160
|
+
/** Loader shares reactive reads, retains fresh idle values, and protects replacement writes. */
|
|
161
|
+
function useCachedLoader({ key, fetch }, { staleTime = DEFAULT_STALE_TIME } = {}) {
|
|
162
|
+
const scope = useScope();
|
|
163
|
+
return useMemo(() => {
|
|
164
|
+
const options = { queryKey: key, queryFn: () => read({ scope, key, fetch }), staleTime, gcTime: gcTimeFor({ staleTime }) };
|
|
165
|
+
return {
|
|
166
|
+
peek: () => scope.client.getQueryData(key),
|
|
167
|
+
load: (required = { key, fetch }) => {
|
|
168
|
+
const selected = { ...options, queryKey: required.key, queryFn: () => read({ scope, key: required.key, fetch: required.fetch }) };
|
|
169
|
+
return scope.client.fetchQuery(selected).catch(error => {
|
|
170
|
+
// A forced refresh can supersede a loader's request without aborting its transport.
|
|
171
|
+
// Follow the new request instead of exposing TanStack's cancellation vocabulary.
|
|
172
|
+
if (!isCancelledError(error))
|
|
173
|
+
throw error;
|
|
174
|
+
// Invalidation also supersedes loader-only reads. Join (or start) the post-write
|
|
175
|
+
// request rather than returning an obsolete value while the key is invalidated.
|
|
176
|
+
const query = scope.client.getQueryCache().find({ queryKey: required.key, exact: true });
|
|
177
|
+
if (query.state.isInvalidated)
|
|
178
|
+
return scope.client.fetchQuery(selected);
|
|
179
|
+
return (query.promise ?? scope.client.getQueryData(required.key));
|
|
180
|
+
});
|
|
181
|
+
},
|
|
182
|
+
replace: ({ value }) => {
|
|
183
|
+
const query = scope.client.getQueryCache().build(scope.client, options);
|
|
184
|
+
const history = historyFor({ scope, query });
|
|
185
|
+
history.replacement += 1;
|
|
186
|
+
history.error = null;
|
|
187
|
+
scope.client.setQueryData(key, value);
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
}, [scope, key, fetch, staleTime]);
|
|
191
|
+
}
|
|
192
|
+
/** A host write/refresh postdates the initial GET as well as a background GET. TanStack
|
|
193
|
+
* normally joins an initial fetch with no data, which would let that pre-write snapshot win.
|
|
194
|
+
* Cancel its cache ownership before requesting the replacement; transports need no abort API. */
|
|
195
|
+
function supersedeInitialRead({ scope, key }, { exact = true } = {}) {
|
|
196
|
+
void scope.client.cancelQueries({ queryKey: key, exact, predicate: query => query.isActive() && query.state.data === undefined && query.state.fetchStatus === 'fetching' });
|
|
197
|
+
}
|
|
198
|
+
/** One invalidation path serves both imperative refreshes and accepted writes. */
|
|
199
|
+
function invalidateResource({ scope, key }, _optional = {}) {
|
|
200
|
+
// A loader-only detail request may feed an active parent query. It is just as stale
|
|
201
|
+
// after a write as an observed read, even though TanStack considers it inactive.
|
|
202
|
+
// Silent cancellation follows the replacement promise instead of resolving old cached data.
|
|
203
|
+
void scope.client.cancelQueries({ queryKey: key, predicate: query => query.state.fetchStatus === 'fetching' }, { silent: true });
|
|
204
|
+
void scope.client.invalidateQueries({ queryKey: key });
|
|
205
|
+
}
|
|
206
|
+
/** Prefix invalidation also reaches child keys read by other mounted consumers. */
|
|
207
|
+
function useInvalidate() {
|
|
208
|
+
const scope = useScope();
|
|
209
|
+
return useCallback(({ key }) => { invalidateResource({ scope, key }); }, [scope]);
|
|
210
|
+
}
|
|
211
|
+
const adapter = { useFetchQuery, useFetchMutation, useCachedLoader, useInvalidate };
|
|
212
|
+
//# sourceMappingURL=adapter.tanstack.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { FetchQueryAdapter } from '@jini-ai/core/fetch';
|
|
3
|
+
/** Internal composition seam: hooks and imperative loaders always use the same provider.
|
|
4
|
+
* Keep the adapter fixed for this provider's lifetime to preserve React hook ordering. */
|
|
5
|
+
export declare function FetchQueryBinding({ adapter, children }: {
|
|
6
|
+
adapter: FetchQueryAdapter;
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
9
|
+
/** Library-free read facade; the provider selects its implementation. */
|
|
10
|
+
export declare const useFetchQuery: FetchQueryAdapter['useFetchQuery'];
|
|
11
|
+
/** Library-free write facade, including safe discarded promises. */
|
|
12
|
+
export declare const useFetchMutation: FetchQueryAdapter['useFetchMutation'];
|
|
13
|
+
/** Prefix invalidator for the nearest provider's cache. */
|
|
14
|
+
export declare const useInvalidate: FetchQueryAdapter['useInvalidate'];
|
|
15
|
+
/** Promise loader using the same cache as reactive reads. */
|
|
16
|
+
export declare const useCachedLoader: FetchQueryAdapter['useCachedLoader'];
|
|
17
|
+
//# sourceMappingURL=binding.react.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext } from 'react';
|
|
3
|
+
const AdapterContext = createContext(null);
|
|
4
|
+
/** Internal composition seam: hooks and imperative loaders always use the same provider.
|
|
5
|
+
* Keep the adapter fixed for this provider's lifetime to preserve React hook ordering. */
|
|
6
|
+
export function FetchQueryBinding({ adapter, children }) {
|
|
7
|
+
return _jsx(AdapterContext.Provider, { value: adapter, children: children });
|
|
8
|
+
}
|
|
9
|
+
/** Resolve the nearest provider; fail before attempting an unscoped read or write. */
|
|
10
|
+
function useAdapter() {
|
|
11
|
+
const adapter = useContext(AdapterContext);
|
|
12
|
+
if (!adapter)
|
|
13
|
+
throw new Error('Fetch-query hooks require FetchQueryProvider');
|
|
14
|
+
return adapter;
|
|
15
|
+
}
|
|
16
|
+
/** Library-free read facade; the provider selects its implementation. */
|
|
17
|
+
export const useFetchQuery = (required, optional = {}) => useAdapter().useFetchQuery(required, optional);
|
|
18
|
+
/** Library-free write facade, including safe discarded promises. */
|
|
19
|
+
export const useFetchMutation = (required, optional = {}) => useAdapter().useFetchMutation(required, optional);
|
|
20
|
+
/** Prefix invalidator for the nearest provider's cache. */
|
|
21
|
+
export const useInvalidate = () => useAdapter().useInvalidate();
|
|
22
|
+
/** Promise loader using the same cache as reactive reads. */
|
|
23
|
+
export const useCachedLoader = (required, optional = {}) => useAdapter().useCachedLoader(required, optional);
|
|
24
|
+
//# sourceMappingURL=binding.react.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FetchQueryEnvironmentPort } from '
|
|
1
|
+
import type { FetchQueryEnvironmentPort } from '@jini-ai/core/fetch';
|
|
2
2
|
/** Browser-only adapter: subscriptions are owned by the provider effect, never module scope. */
|
|
3
3
|
export declare const browserFetchQueryEnvironment: FetchQueryEnvironmentPort;
|
|
4
4
|
//# sourceMappingURL=environment.browser.d.ts.map
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
export { FetchQueryProvider
|
|
2
|
-
export
|
|
3
|
-
|
|
1
|
+
export { FetchQueryProvider } from './adapter.react.js';
|
|
2
|
+
export { useFetchQuery, useFetchMutation, useCachedLoader, useInvalidate } from './binding.react.js';
|
|
3
|
+
/** @deprecated Import the framework-neutral environment port from @jini-ai/core/fetch. */
|
|
4
|
+
export type { FetchQueryEnvironmentPort } from '@jini-ai/core/fetch';
|
|
5
|
+
/** @deprecated Import framework-neutral query contracts from @jini-ai/core/fetch. */
|
|
6
|
+
export type { QueryKey, QueryStatus, QueryResult, FetchQueryOptions, MutationStatus, MutationResult, FetchMutationOptions, CachedLoaderOptions, CachedLoader, FetchQueryAdapter } from '@jini-ai/core/fetch';
|
|
4
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export { FetchQueryProvider
|
|
1
|
+
export { FetchQueryProvider } from './adapter.react.js';
|
|
2
|
+
export { useFetchQuery, useFetchMutation, useCachedLoader, useInvalidate } from './binding.react.js';
|
|
2
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Optional adapter entry. Importing the default entry never loads TanStack. */
|
|
2
|
+
export { FetchQueryProvider } from './adapter.tanstack.js';
|
|
3
|
+
export { useFetchQuery, useFetchMutation, useCachedLoader, useInvalidate } from './binding.react.js';
|
|
4
|
+
/** @deprecated Import the framework-neutral environment port from @jini-ai/core/fetch. */
|
|
5
|
+
export type { FetchQueryEnvironmentPort } from '@jini-ai/core/fetch';
|
|
6
|
+
/** @deprecated Import framework-neutral query contracts from @jini-ai/core/fetch. */
|
|
7
|
+
export type { QueryKey, QueryStatus, QueryResult, FetchQueryOptions, MutationStatus, MutationResult, FetchMutationOptions, CachedLoaderOptions, CachedLoader, FetchQueryAdapter } from '@jini-ai/core/fetch';
|
|
8
|
+
//# sourceMappingURL=tanstack.d.ts.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Optional adapter entry. Importing the default entry never loads TanStack. */
|
|
2
|
+
export { FetchQueryProvider } from './adapter.tanstack.js';
|
|
3
|
+
export { useFetchQuery, useFetchMutation, useCachedLoader, useInvalidate } from './binding.react.js';
|
|
4
|
+
//# sourceMappingURL=tanstack.js.map
|
|
@@ -4,5 +4,7 @@ export declare function standingDraftRecoveryMessage({ draft, t, serverUpdatedAt
|
|
|
4
4
|
draft: StandingDraftAutosaveSnapshot;
|
|
5
5
|
t: (key: string) => string;
|
|
6
6
|
serverUpdatedAt?: string;
|
|
7
|
-
},
|
|
7
|
+
}, { formatSavedAt }?: {
|
|
8
|
+
formatSavedAt?: (iso: string) => string;
|
|
9
|
+
}): string;
|
|
8
10
|
//# sourceMappingURL=standing-draft-recovery-message.d.ts.map
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import { formatTimestamp } from "./format-timestamp.js";
|
|
2
|
+
/** The viewer's wall-clock time of the capture, `YYYY-MM-DD HH:MM`. The raw ISO string read as
|
|
3
|
+
* "from 2026-10-11T19:26:00.665Z" in the restore banner (2026-10-11): UTC and milliseconds the
|
|
4
|
+
* operator never thinks in. The draft was captured in this browser, so local time is the honest one. */
|
|
5
|
+
function formatSavedAtLocal(iso) {
|
|
6
|
+
return formatTimestamp({ iso }, { timeZone: "local" });
|
|
7
|
+
}
|
|
1
8
|
/** Compare timestamps explicitly; restoration only changes the working copy, never the server. */
|
|
2
|
-
export function standingDraftRecoveryMessage({ draft, t, serverUpdatedAt },
|
|
9
|
+
export function standingDraftRecoveryMessage({ draft, t, serverUpdatedAt }, { formatSavedAt = formatSavedAtLocal } = {}) {
|
|
3
10
|
const captured = Date.parse(draft.savedAt);
|
|
4
11
|
const server = Date.parse(serverUpdatedAt ?? draft.serverUpdatedAt ?? "");
|
|
5
12
|
const comparison = server > captured ? "Server content is newer."
|
|
6
13
|
: server < captured ? "Local changes are newer."
|
|
7
14
|
: server === captured ? "Both copies have the same timestamp." : "";
|
|
8
|
-
return `${t("Restore unsaved changes from")} ${draft.savedAt}${comparison ? ` · ${t(comparison)}` : ""}`;
|
|
15
|
+
return `${t("Restore unsaved changes from")} ${formatSavedAt(draft.savedAt)}${comparison ? ` · ${t(comparison)}` : ""}`;
|
|
9
16
|
}
|
|
10
17
|
//# sourceMappingURL=standing-draft-recovery-message.js.map
|
|
@@ -95,6 +95,8 @@
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
.jini-input {
|
|
98
|
+
min-height: var(--jini-control-h, 37px);
|
|
99
|
+
box-sizing: border-box;
|
|
98
100
|
width: 100%;
|
|
99
101
|
min-width: 0;
|
|
100
102
|
padding: 8px 10px;
|
|
@@ -107,6 +109,17 @@
|
|
|
107
109
|
transition: border-color 120ms var(--jini-ease-out), box-shadow 120ms var(--jini-ease-out);
|
|
108
110
|
}
|
|
109
111
|
|
|
112
|
+
/* Native selects share one affordance across execution settings and host forms. */
|
|
113
|
+
select.jini-input {
|
|
114
|
+
appearance: none;
|
|
115
|
+
padding-right: 2rem;
|
|
116
|
+
cursor: pointer;
|
|
117
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%236b7280' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
|
118
|
+
background-repeat: no-repeat;
|
|
119
|
+
background-position: right 0.7rem center;
|
|
120
|
+
background-size: 10px 6px;
|
|
121
|
+
}
|
|
122
|
+
|
|
110
123
|
.jini-input:focus {
|
|
111
124
|
outline: none;
|
|
112
125
|
border-color: var(--jini-accent);
|
|
@@ -127,6 +140,8 @@
|
|
|
127
140
|
.jini-settings-section .jini-btn,
|
|
128
141
|
.jini-settings-section .jini-button,
|
|
129
142
|
.jini-settings-section a.jini-button {
|
|
143
|
+
min-height: var(--jini-control-h, 37px);
|
|
144
|
+
box-sizing: border-box;
|
|
130
145
|
display: inline-flex;
|
|
131
146
|
align-items: center;
|
|
132
147
|
justify-content: center;
|
|
@@ -394,6 +409,21 @@
|
|
|
394
409
|
|
|
395
410
|
`align-items: start` so a field with a two-line hint (an invalid base URL) does not stretch its
|
|
396
411
|
neighbour's input to match. */
|
|
412
|
+
/* `ByokProviderForm`'s `collapseAdvanced`: Base URL + Max tokens behind one disclosure after Model. */
|
|
413
|
+
.jini-byok-advanced > summary {
|
|
414
|
+
cursor: pointer;
|
|
415
|
+
width: max-content;
|
|
416
|
+
font-size: 12px;
|
|
417
|
+
font-weight: 600;
|
|
418
|
+
color: var(--jini-text-muted);
|
|
419
|
+
}
|
|
420
|
+
.jini-byok-advanced > summary:hover { color: var(--jini-text-strong); }
|
|
421
|
+
.jini-byok-advanced[open] > summary { margin-bottom: 12px; }
|
|
422
|
+
|
|
423
|
+
/* `ByokProviderForm`'s `apiKeyActions`: the host's button row directly under the key input (Show
|
|
424
|
+
stays on the input's line). Wraps on a narrow card. */
|
|
425
|
+
.jini-byok-key-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 2px; }
|
|
426
|
+
|
|
397
427
|
.jini-byok-field-row {
|
|
398
428
|
display: flex;
|
|
399
429
|
flex-wrap: wrap;
|
|
@@ -479,13 +509,25 @@
|
|
|
479
509
|
|
|
480
510
|
/* Agent cards. The origin drew a responsive grid of selectable vendor cards;
|
|
481
511
|
`auto-fill` keeps it one column inside a narrow settings panel and two or
|
|
482
|
-
more when the host gives the dialog room.
|
|
512
|
+
more when the host gives the dialog room.
|
|
513
|
+
|
|
514
|
+
Settings grow inside the selected card's own column; top alignment keeps
|
|
515
|
+
its neighbour at its normal height. */
|
|
483
516
|
.jini-agent-grid {
|
|
484
517
|
display: grid;
|
|
518
|
+
align-items: start;
|
|
485
519
|
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
|
486
520
|
gap: 10px;
|
|
487
521
|
}
|
|
488
522
|
|
|
523
|
+
/* "Show N not installed" — the uninstalled tail of the grid sits behind this toggle. */
|
|
524
|
+
.jini-local-cli-more {
|
|
525
|
+
display: block;
|
|
526
|
+
width: auto;
|
|
527
|
+
align-self: flex-start;
|
|
528
|
+
margin: 10px 0;
|
|
529
|
+
}
|
|
530
|
+
|
|
489
531
|
.jini-agent-card {
|
|
490
532
|
display: flex;
|
|
491
533
|
flex-direction: column;
|
|
@@ -500,6 +542,7 @@
|
|
|
500
542
|
}
|
|
501
543
|
|
|
502
544
|
.jini-agent-card.is-selected {
|
|
545
|
+
grid-column: span 1;
|
|
503
546
|
border-color: var(--jini-accent);
|
|
504
547
|
box-shadow: 0 0 0 1px var(--jini-accent);
|
|
505
548
|
}
|
|
@@ -532,30 +575,26 @@
|
|
|
532
575
|
|
|
533
576
|
/* The whole card is the click target, not just the text at the top of it.
|
|
534
577
|
*
|
|
535
|
-
*
|
|
536
|
-
*
|
|
537
|
-
* content height. The space the row-mate's expansion added was therefore
|
|
538
|
-
* inert: clicking the lower two-thirds of a stretched-but-unselected card did
|
|
539
|
-
* nothing, which reads as a broken card rather than as "aim higher".
|
|
578
|
+
* The select button owns the whole header, including its padding, when no
|
|
579
|
+
* other controls need that space.
|
|
540
580
|
*
|
|
541
581
|
* `:last-child` is load-bearing. A card renders its diagnostics, model config,
|
|
542
582
|
* test result and path-repair actions as SIBLINGS after `-main`, and those
|
|
543
583
|
* blocks contain their own buttons; growing `-main` unconditionally would push
|
|
544
584
|
* them to the card's bottom edge, and a full-card overlay would swallow their
|
|
545
585
|
* clicks outright. `-main:last-child` is true exactly when nothing rendered
|
|
546
|
-
* after it — the
|
|
586
|
+
* after it — the no-diagnostics case this bug is about.
|
|
547
587
|
*
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
|
|
551
|
-
.jini-agent-card:not(.is-selected) .jini-agent-card-main:last-child {
|
|
588
|
+
* Test stays in the selected card's header; settings follow `-main`, keeping
|
|
589
|
+
* both their controls and the header's Test button independently clickable. */
|
|
590
|
+
.jini-agent-card .jini-agent-card-main:last-child {
|
|
552
591
|
flex: 1 1 auto;
|
|
553
592
|
/* Handed to the button below — left here it would ring the card in 12px of
|
|
554
593
|
unclickable margin, a smaller version of the same bug. */
|
|
555
594
|
padding: 0;
|
|
556
595
|
}
|
|
557
596
|
|
|
558
|
-
.jini-agent-card
|
|
597
|
+
.jini-agent-card .jini-agent-card-main:last-child > .jini-agent-card-select {
|
|
559
598
|
/* The row is `align-items: flex-start` so the Test button never stretches;
|
|
560
599
|
this opts the select button alone into filling the card. Its own
|
|
561
600
|
`align-items: flex-start` keeps icon and text at the top — only the hit
|
|
@@ -605,15 +644,15 @@
|
|
|
605
644
|
color: var(--jini-text);
|
|
606
645
|
}
|
|
607
646
|
|
|
608
|
-
.jini-agent-card-name-divider {
|
|
609
|
-
color: var(--jini-text-disabled);
|
|
610
|
-
}
|
|
611
|
-
|
|
612
647
|
.jini-agent-card-tagline {
|
|
613
648
|
font-size: 12px;
|
|
614
649
|
color: var(--jini-text-muted);
|
|
615
650
|
}
|
|
616
651
|
|
|
652
|
+
.jini-agent-card.is-selected .jini-agent-card-tagline:not(:empty)::before {
|
|
653
|
+
content: '·\00a0';
|
|
654
|
+
}
|
|
655
|
+
|
|
617
656
|
.jini-agent-card-badges {
|
|
618
657
|
display: flex;
|
|
619
658
|
flex-wrap: wrap;
|
|
@@ -657,14 +696,98 @@
|
|
|
657
696
|
opacity: 0.7;
|
|
658
697
|
}
|
|
659
698
|
|
|
660
|
-
.
|
|
699
|
+
/* Selection reads as the accent ring plus this check, never as a bigger card. */
|
|
700
|
+
.jini-agent-card-check {
|
|
701
|
+
flex: 0 0 auto;
|
|
702
|
+
display: grid;
|
|
703
|
+
place-items: center;
|
|
704
|
+
width: 18px;
|
|
705
|
+
height: 18px;
|
|
706
|
+
margin-left: auto;
|
|
707
|
+
border-radius: 50%;
|
|
708
|
+
background: var(--jini-accent);
|
|
709
|
+
color: var(--jini-accent-ink);
|
|
710
|
+
font-size: 11px;
|
|
711
|
+
font-weight: 700;
|
|
712
|
+
line-height: 1;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/* Settings stay inside the selected card, with each label above its control
|
|
716
|
+
and the model's provenance sentence visible below the picker. */
|
|
717
|
+
.jini-agent-settings {
|
|
661
718
|
display: flex;
|
|
662
719
|
flex-direction: column;
|
|
663
|
-
gap:
|
|
664
|
-
padding:
|
|
720
|
+
gap: 8px;
|
|
721
|
+
padding: 10px 12px;
|
|
665
722
|
border-top: 1px solid var(--jini-border);
|
|
666
|
-
|
|
667
|
-
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
.jini-agent-settings-row,
|
|
726
|
+
.jini-agent-settings-tail {
|
|
727
|
+
display: flex;
|
|
728
|
+
flex-direction: column;
|
|
729
|
+
align-items: stretch;
|
|
730
|
+
gap: 8px 16px;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.jini-agent-settings-tail {
|
|
734
|
+
gap: 8px 10px;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/* Wide enough for "Testing…", so starting a test never reflows its controls. */
|
|
738
|
+
.jini-agent-settings-tail > .jini-agent-card-test {
|
|
739
|
+
min-width: 5.5rem;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
.jini-agent-settings-field {
|
|
743
|
+
display: flex;
|
|
744
|
+
flex-direction: column;
|
|
745
|
+
align-items: stretch;
|
|
746
|
+
gap: 4px;
|
|
747
|
+
min-width: 0;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
.jini-agent-settings-label {
|
|
751
|
+
display: flex;
|
|
752
|
+
align-items: center;
|
|
753
|
+
flex-wrap: wrap;
|
|
754
|
+
gap: 6px;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
.jini-agent-settings-field > .jini-field-label {
|
|
758
|
+
white-space: nowrap;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
.jini-agent-settings .jini-searchable-select,
|
|
762
|
+
.jini-agent-settings select.jini-input,
|
|
763
|
+
.jini-agent-settings .jini-agent-settings-custom {
|
|
764
|
+
width: 100%;
|
|
765
|
+
min-width: 0;
|
|
766
|
+
max-width: none;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
.jini-agent-settings-source {
|
|
770
|
+
display: inline-flex;
|
|
771
|
+
align-items: center;
|
|
772
|
+
gap: 2px;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
.jini-agent-settings-source > .jini-agent-model-source {
|
|
776
|
+
margin-left: 0;
|
|
777
|
+
white-space: nowrap;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
.jini-agent-settings .jini-agent-card-test-result {
|
|
781
|
+
padding: 0;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
.jini-agent-settings .jini-agent-card-path-repair {
|
|
785
|
+
margin: 0;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
.jini-agent-settings .jini-agent-cli-env {
|
|
789
|
+
margin: 0;
|
|
790
|
+
padding-top: 8px;
|
|
668
791
|
}
|
|
669
792
|
|
|
670
793
|
/* The source badge is load-bearing, not decoration: a built-in list can be
|
|
@@ -895,7 +1018,21 @@
|
|
|
895
1018
|
width: 100%;
|
|
896
1019
|
}
|
|
897
1020
|
|
|
1021
|
+
/* Hosts may pass the input class to the wrapper; only the trigger paints the control. */
|
|
1022
|
+
.jini-select.jini-input {
|
|
1023
|
+
padding: 0;
|
|
1024
|
+
border: 0;
|
|
1025
|
+
background: none;
|
|
1026
|
+
box-shadow: none;
|
|
1027
|
+
min-height: 0;
|
|
1028
|
+
}
|
|
1029
|
+
.jini-select.is-missing > .jini-select-trigger {
|
|
1030
|
+
border-color: color-mix(in srgb, var(--jini-danger) 55%, var(--jini-border));
|
|
1031
|
+
}
|
|
1032
|
+
|
|
898
1033
|
.jini-select-trigger {
|
|
1034
|
+
min-height: var(--jini-control-h, 37px);
|
|
1035
|
+
box-sizing: border-box;
|
|
899
1036
|
display: flex;
|
|
900
1037
|
align-items: center;
|
|
901
1038
|
justify-content: space-between;
|
|
@@ -912,6 +1049,17 @@
|
|
|
912
1049
|
cursor: pointer;
|
|
913
1050
|
}
|
|
914
1051
|
|
|
1052
|
+
.jini-select-trigger:focus-visible {
|
|
1053
|
+
outline: none;
|
|
1054
|
+
border-color: var(--jini-accent);
|
|
1055
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--jini-accent) 18%, transparent);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
@media (max-width: 640px) {
|
|
1059
|
+
.jini-input,
|
|
1060
|
+
.jini-select-trigger { font-size: 16px; min-height: 40px; }
|
|
1061
|
+
}
|
|
1062
|
+
|
|
915
1063
|
.jini-select-trigger:hover:not(:disabled) {
|
|
916
1064
|
border-color: var(--jini-border-strong);
|
|
917
1065
|
}
|