@entifix/next-shell 0.1.0-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +7 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/back-office/account-menu.d.ts +29 -0
- package/dist/lib/back-office/account-menu.d.ts.map +1 -0
- package/dist/lib/back-office/account-menu.js +70 -0
- package/dist/lib/back-office/account-menu.js.map +1 -0
- package/dist/lib/back-office/back-office-shell.d.ts +50 -0
- package/dist/lib/back-office/back-office-shell.d.ts.map +1 -0
- package/dist/lib/back-office/back-office-shell.js +128 -0
- package/dist/lib/back-office/back-office-shell.js.map +1 -0
- package/dist/lib/back-office/breadcrumbs.d.ts +16 -0
- package/dist/lib/back-office/breadcrumbs.d.ts.map +1 -0
- package/dist/lib/back-office/breadcrumbs.js +53 -0
- package/dist/lib/back-office/breadcrumbs.js.map +1 -0
- package/dist/lib/back-office/group-by-screen-type.d.ts +21 -0
- package/dist/lib/back-office/group-by-screen-type.d.ts.map +1 -0
- package/dist/lib/back-office/group-by-screen-type.js +39 -0
- package/dist/lib/back-office/group-by-screen-type.js.map +1 -0
- package/dist/lib/back-office/index.d.ts +6 -0
- package/dist/lib/back-office/index.d.ts.map +1 -0
- package/dist/lib/back-office/index.js +7 -0
- package/dist/lib/back-office/index.js.map +1 -0
- package/dist/lib/back-office/nav.d.ts +39 -0
- package/dist/lib/back-office/nav.d.ts.map +1 -0
- package/dist/lib/back-office/nav.js +3 -0
- package/dist/lib/back-office/nav.js.map +1 -0
- package/dist/lib/back-office/sidebar-nav.d.ts +26 -0
- package/dist/lib/back-office/sidebar-nav.d.ts.map +1 -0
- package/dist/lib/back-office/sidebar-nav.js +181 -0
- package/dist/lib/back-office/sidebar-nav.js.map +1 -0
- package/dist/lib/command-palette/command-palette-host.d.ts +41 -0
- package/dist/lib/command-palette/command-palette-host.d.ts.map +1 -0
- package/dist/lib/command-palette/command-palette-host.js +196 -0
- package/dist/lib/command-palette/command-palette-host.js.map +1 -0
- package/dist/lib/command-palette/index.d.ts +9 -0
- package/dist/lib/command-palette/index.d.ts.map +1 -0
- package/dist/lib/command-palette/index.js +10 -0
- package/dist/lib/command-palette/index.js.map +1 -0
- package/dist/lib/command-palette/palette-command.d.ts +32 -0
- package/dist/lib/command-palette/palette-command.d.ts.map +1 -0
- package/dist/lib/command-palette/palette-command.js +19 -0
- package/dist/lib/command-palette/palette-command.js.map +1 -0
- package/dist/lib/command-palette/use-command-recency.d.ts +28 -0
- package/dist/lib/command-palette/use-command-recency.d.ts.map +1 -0
- package/dist/lib/command-palette/use-command-recency.js +67 -0
- package/dist/lib/command-palette/use-command-recency.js.map +1 -0
- package/dist/lib/command-palette/use-command-source.d.ts +17 -0
- package/dist/lib/command-palette/use-command-source.d.ts.map +1 -0
- package/dist/lib/command-palette/use-command-source.js +70 -0
- package/dist/lib/command-palette/use-command-source.js.map +1 -0
- package/dist/lib/command-palette/use-nav-source.d.ts +21 -0
- package/dist/lib/command-palette/use-nav-source.d.ts.map +1 -0
- package/dist/lib/command-palette/use-nav-source.js +78 -0
- package/dist/lib/command-palette/use-nav-source.js.map +1 -0
- package/dist/lib/command-palette/use-records-source.d.ts +23 -0
- package/dist/lib/command-palette/use-records-source.d.ts.map +1 -0
- package/dist/lib/command-palette/use-records-source.js +199 -0
- package/dist/lib/command-palette/use-records-source.js.map +1 -0
- package/dist/lib/command-palette/use-tabs-source.d.ts +20 -0
- package/dist/lib/command-palette/use-tabs-source.d.ts.map +1 -0
- package/dist/lib/command-palette/use-tabs-source.js +52 -0
- package/dist/lib/command-palette/use-tabs-source.js.map +1 -0
- package/dist/lib/command-palette/use-use-cases-source.d.ts +22 -0
- package/dist/lib/command-palette/use-use-cases-source.d.ts.map +1 -0
- package/dist/lib/command-palette/use-use-cases-source.js +93 -0
- package/dist/lib/command-palette/use-use-cases-source.js.map +1 -0
- package/dist/lib/config/config-route.d.ts +51 -0
- package/dist/lib/config/config-route.d.ts.map +1 -0
- package/dist/lib/config/config-route.js +65 -0
- package/dist/lib/config/config-route.js.map +1 -0
- package/dist/lib/config/service-proxy-route.d.ts +28 -0
- package/dist/lib/config/service-proxy-route.d.ts.map +1 -0
- package/dist/lib/config/service-proxy-route.js +125 -0
- package/dist/lib/config/service-proxy-route.js.map +1 -0
- package/dist/lib/config/service-token.d.ts +5 -0
- package/dist/lib/config/service-token.d.ts.map +1 -0
- package/dist/lib/config/service-token.js +18 -0
- package/dist/lib/config/service-token.js.map +1 -0
- package/dist/lib/crud/entity-crud-form.d.ts +49 -0
- package/dist/lib/crud/entity-crud-form.d.ts.map +1 -0
- package/dist/lib/crud/entity-crud-form.js +133 -0
- package/dist/lib/crud/entity-crud-form.js.map +1 -0
- package/dist/lib/crud/hand-off-write.d.ts +35 -0
- package/dist/lib/crud/hand-off-write.d.ts.map +1 -0
- package/dist/lib/crud/hand-off-write.js +27 -0
- package/dist/lib/crud/hand-off-write.js.map +1 -0
- package/dist/lib/crud/index.d.ts +9 -0
- package/dist/lib/crud/index.d.ts.map +1 -0
- package/dist/lib/crud/index.js +10 -0
- package/dist/lib/crud/index.js.map +1 -0
- package/dist/lib/crud/make-entity-crud.d.ts +28 -0
- package/dist/lib/crud/make-entity-crud.d.ts.map +1 -0
- package/dist/lib/crud/make-entity-crud.js +318 -0
- package/dist/lib/crud/make-entity-crud.js.map +1 -0
- package/dist/lib/crud/make-entity-crud.types.d.ts +237 -0
- package/dist/lib/crud/make-entity-crud.types.d.ts.map +1 -0
- package/dist/lib/crud/make-entity-crud.types.js +6 -0
- package/dist/lib/crud/make-entity-crud.types.js.map +1 -0
- package/dist/lib/crud/pending-notice.d.ts +31 -0
- package/dist/lib/crud/pending-notice.d.ts.map +1 -0
- package/dist/lib/crud/pending-notice.js +72 -0
- package/dist/lib/crud/pending-notice.js.map +1 -0
- package/dist/lib/crud/slug.d.ts +13 -0
- package/dist/lib/crud/slug.d.ts.map +1 -0
- package/dist/lib/crud/slug.js +13 -0
- package/dist/lib/crud/slug.js.map +1 -0
- package/dist/lib/crud/use-entity-affordances.d.ts +20 -0
- package/dist/lib/crud/use-entity-affordances.d.ts.map +1 -0
- package/dist/lib/crud/use-entity-affordances.js +22 -0
- package/dist/lib/crud/use-entity-affordances.js.map +1 -0
- package/dist/lib/crud/use-entity-bulk.d.ts +43 -0
- package/dist/lib/crud/use-entity-bulk.d.ts.map +1 -0
- package/dist/lib/crud/use-entity-bulk.js +106 -0
- package/dist/lib/crud/use-entity-bulk.js.map +1 -0
- package/dist/lib/crud/use-entity-link-sources.d.ts +25 -0
- package/dist/lib/crud/use-entity-link-sources.d.ts.map +1 -0
- package/dist/lib/crud/use-entity-link-sources.js +37 -0
- package/dist/lib/crud/use-entity-link-sources.js.map +1 -0
- package/dist/lib/health/health-routes.d.ts +37 -0
- package/dist/lib/health/health-routes.d.ts.map +1 -0
- package/dist/lib/health/health-routes.js +90 -0
- package/dist/lib/health/health-routes.js.map +1 -0
- package/dist/lib/i18n/catalog/en.d.ts +4 -0
- package/dist/lib/i18n/catalog/en.d.ts.map +1 -0
- package/dist/lib/i18n/catalog/en.js +347 -0
- package/dist/lib/i18n/catalog/en.js.map +1 -0
- package/dist/lib/i18n/catalog/es.d.ts +397 -0
- package/dist/lib/i18n/catalog/es.d.ts.map +1 -0
- package/dist/lib/i18n/catalog/es.js +407 -0
- package/dist/lib/i18n/catalog/es.js.map +1 -0
- package/dist/lib/i18n/catalog/index.d.ts +671 -0
- package/dist/lib/i18n/catalog/index.d.ts.map +1 -0
- package/dist/lib/i18n/catalog/index.js +28 -0
- package/dist/lib/i18n/catalog/index.js.map +1 -0
- package/dist/lib/i18n/index.d.ts +2 -0
- package/dist/lib/i18n/index.d.ts.map +1 -0
- package/dist/lib/i18n/index.js +3 -0
- package/dist/lib/i18n/index.js.map +1 -0
- package/dist/lib/i18n/locale-link.d.ts +23 -0
- package/dist/lib/i18n/locale-link.d.ts.map +1 -0
- package/dist/lib/i18n/locale-link.js +43 -0
- package/dist/lib/i18n/locale-link.js.map +1 -0
- package/dist/lib/i18n/spec-catalog.d.ts +2 -0
- package/dist/lib/i18n/spec-catalog.d.ts.map +1 -0
- package/dist/lib/i18n/spec-catalog.js +84 -0
- package/dist/lib/i18n/spec-catalog.js.map +1 -0
- package/dist/lib/search/record-search-route.d.ts +44 -0
- package/dist/lib/search/record-search-route.d.ts.map +1 -0
- package/dist/lib/search/record-search-route.js +158 -0
- package/dist/lib/search/record-search-route.js.map +1 -0
- package/dist/lib/search/record-search-source.d.ts +59 -0
- package/dist/lib/search/record-search-source.d.ts.map +1 -0
- package/dist/lib/search/record-search-source.js +118 -0
- package/dist/lib/search/record-search-source.js.map +1 -0
- package/dist/lib/search/record-search.types.d.ts +85 -0
- package/dist/lib/search/record-search.types.d.ts.map +1 -0
- package/dist/lib/search/record-search.types.js +29 -0
- package/dist/lib/search/record-search.types.js.map +1 -0
- package/dist/lib/search/search-records.d.ts +25 -0
- package/dist/lib/search/search-records.d.ts.map +1 -0
- package/dist/lib/search/search-records.js +36 -0
- package/dist/lib/search/search-records.js.map +1 -0
- package/dist/lib/session/account-links.d.ts +46 -0
- package/dist/lib/session/account-links.d.ts.map +1 -0
- package/dist/lib/session/account-links.js +41 -0
- package/dist/lib/session/account-links.js.map +1 -0
- package/dist/lib/session/bearer.d.ts +25 -0
- package/dist/lib/session/bearer.d.ts.map +1 -0
- package/dist/lib/session/bearer.js +31 -0
- package/dist/lib/session/bearer.js.map +1 -0
- package/dist/lib/session/cookies.d.ts +14 -0
- package/dist/lib/session/cookies.d.ts.map +1 -0
- package/dist/lib/session/cookies.js +33 -0
- package/dist/lib/session/cookies.js.map +1 -0
- package/dist/lib/session/device.d.ts +31 -0
- package/dist/lib/session/device.d.ts.map +1 -0
- package/dist/lib/session/device.js +80 -0
- package/dist/lib/session/device.js.map +1 -0
- package/dist/lib/session/index.d.ts +3 -0
- package/dist/lib/session/index.d.ts.map +1 -0
- package/dist/lib/session/index.js +12 -0
- package/dist/lib/session/index.js.map +1 -0
- package/dist/lib/session/refresh-route.d.ts +19 -0
- package/dist/lib/session/refresh-route.d.ts.map +1 -0
- package/dist/lib/session/refresh-route.js +85 -0
- package/dist/lib/session/refresh-route.js.map +1 -0
- package/dist/lib/session/session-keepalive.d.ts +52 -0
- package/dist/lib/session/session-keepalive.d.ts.map +1 -0
- package/dist/lib/session/session-keepalive.js +72 -0
- package/dist/lib/session/session-keepalive.js.map +1 -0
- package/dist/lib/session/use-session-refresh.d.ts +43 -0
- package/dist/lib/session/use-session-refresh.d.ts.map +1 -0
- package/dist/lib/session/use-session-refresh.js +120 -0
- package/dist/lib/session/use-session-refresh.js.map +1 -0
- package/dist/lib/wizard/index.d.ts +4 -0
- package/dist/lib/wizard/index.d.ts.map +1 -0
- package/dist/lib/wizard/index.js +5 -0
- package/dist/lib/wizard/index.js.map +1 -0
- package/dist/lib/wizard/use-wizard-draft.d.ts +22 -0
- package/dist/lib/wizard/use-wizard-draft.d.ts.map +1 -0
- package/dist/lib/wizard/use-wizard-draft.js +39 -0
- package/dist/lib/wizard/use-wizard-draft.js.map +1 -0
- package/dist/lib/wizard/use-wizard-step-param.d.ts +60 -0
- package/dist/lib/wizard/use-wizard-step-param.d.ts.map +1 -0
- package/dist/lib/wizard/use-wizard-step-param.js +94 -0
- package/dist/lib/wizard/use-wizard-step-param.js.map +1 -0
- package/dist/lib/wizard/wizard-tab-kind.d.ts +31 -0
- package/dist/lib/wizard/wizard-tab-kind.d.ts.map +1 -0
- package/dist/lib/wizard/wizard-tab-kind.js +33 -0
- package/dist/lib/wizard/wizard-tab-kind.js.map +1 -0
- package/dist/lib/workspace/drafts-state.d.ts +88 -0
- package/dist/lib/workspace/drafts-state.d.ts.map +1 -0
- package/dist/lib/workspace/drafts-state.js +128 -0
- package/dist/lib/workspace/drafts-state.js.map +1 -0
- package/dist/lib/workspace/entity-nav.d.ts +26 -0
- package/dist/lib/workspace/entity-nav.d.ts.map +1 -0
- package/dist/lib/workspace/entity-nav.js +56 -0
- package/dist/lib/workspace/entity-nav.js.map +1 -0
- package/dist/lib/workspace/entity-tab-kind.d.ts +51 -0
- package/dist/lib/workspace/entity-tab-kind.d.ts.map +1 -0
- package/dist/lib/workspace/entity-tab-kind.js +47 -0
- package/dist/lib/workspace/entity-tab-kind.js.map +1 -0
- package/dist/lib/workspace/idb-state-storage.d.ts +9 -0
- package/dist/lib/workspace/idb-state-storage.d.ts.map +1 -0
- package/dist/lib/workspace/idb-state-storage.js +32 -0
- package/dist/lib/workspace/idb-state-storage.js.map +1 -0
- package/dist/lib/workspace/index.d.ts +13 -0
- package/dist/lib/workspace/index.d.ts.map +1 -0
- package/dist/lib/workspace/index.js +14 -0
- package/dist/lib/workspace/index.js.map +1 -0
- package/dist/lib/workspace/pending-state.d.ts +84 -0
- package/dist/lib/workspace/pending-state.d.ts.map +1 -0
- package/dist/lib/workspace/pending-state.js +155 -0
- package/dist/lib/workspace/pending-state.js.map +1 -0
- package/dist/lib/workspace/pending-transactions.d.ts +44 -0
- package/dist/lib/workspace/pending-transactions.d.ts.map +1 -0
- package/dist/lib/workspace/pending-transactions.js +114 -0
- package/dist/lib/workspace/pending-transactions.js.map +1 -0
- package/dist/lib/workspace/tab-kind.d.ts +48 -0
- package/dist/lib/workspace/tab-kind.d.ts.map +1 -0
- package/dist/lib/workspace/tab-kind.js +47 -0
- package/dist/lib/workspace/tab-kind.js.map +1 -0
- package/dist/lib/workspace/tab-state.d.ts +36 -0
- package/dist/lib/workspace/tab-state.d.ts.map +1 -0
- package/dist/lib/workspace/tab-state.js +81 -0
- package/dist/lib/workspace/tab-state.js.map +1 -0
- package/dist/lib/workspace/tabs-state.d.ts +46 -0
- package/dist/lib/workspace/tabs-state.d.ts.map +1 -0
- package/dist/lib/workspace/tabs-state.js +56 -0
- package/dist/lib/workspace/tabs-state.js.map +1 -0
- package/dist/lib/workspace/use-entity-draft.d.ts +25 -0
- package/dist/lib/workspace/use-entity-draft.d.ts.map +1 -0
- package/dist/lib/workspace/use-entity-draft.js +38 -0
- package/dist/lib/workspace/use-entity-draft.js.map +1 -0
- package/dist/lib/workspace/workspace-scope.d.ts +51 -0
- package/dist/lib/workspace/workspace-scope.d.ts.map +1 -0
- package/dist/lib/workspace/workspace-scope.js +42 -0
- package/dist/lib/workspace/workspace-scope.js.map +1 -0
- package/dist/lib/workspace/workspace-shell.d.ts +33 -0
- package/dist/lib/workspace/workspace-shell.d.ts.map +1 -0
- package/dist/lib/workspace/workspace-shell.js +206 -0
- package/dist/lib/workspace/workspace-shell.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +41 -0
- package/dist/server.js.map +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ConfirmDialog, Tab, TabStrip, TopBar, useT, useTranslateKey } from '@entifix/react-controls';
|
|
4
|
+
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
|
5
|
+
import { useEffect, useState } from 'react';
|
|
6
|
+
import { useDraftsState } from './drafts-state.js';
|
|
7
|
+
import { useTabsState } from './tabs-state.js';
|
|
8
|
+
/**
|
|
9
|
+
* The tab workspace: a strip of persisted tabs over the active tab's body — no
|
|
10
|
+
* sidebar or brand of its own. It is mounted inside a host shell (the
|
|
11
|
+
* back-office layout, say) that already supplies those, so nesting two
|
|
12
|
+
* sidebars never happens. The open set lives in {@link useTabsState}
|
|
13
|
+
* (IndexedDB); the URL's `?tab=` projects only the active tab, so a deep link
|
|
14
|
+
* opens or focuses exactly that tab and an unknown kind shows the fallback
|
|
15
|
+
* instead of crashing.
|
|
16
|
+
*/ export function WorkspaceShell({ scope, registry, actions, fallback, emptyState }) {
|
|
17
|
+
const t = useT('shell');
|
|
18
|
+
// Tab captions are catalog keys carried in a registry, not authored copy.
|
|
19
|
+
const translate = useTranslateKey();
|
|
20
|
+
const searchParams = useSearchParams();
|
|
21
|
+
const router = useRouter();
|
|
22
|
+
const pathname = usePathname();
|
|
23
|
+
const urlTab = searchParams.get('tab');
|
|
24
|
+
const tabs = useTabsState((state)=>state.tabs);
|
|
25
|
+
const activeParam = useTabsState((state)=>state.activeParam);
|
|
26
|
+
const open = useTabsState((state)=>state.open);
|
|
27
|
+
const close = useTabsState((state)=>state.close);
|
|
28
|
+
const activate = useTabsState((state)=>state.activate);
|
|
29
|
+
const drafts = useDraftsState((state)=>state.drafts);
|
|
30
|
+
const clearDraft = useDraftsState((state)=>state.clearDraft);
|
|
31
|
+
// Load the persisted tab set and drafts once, on the client (hydration is
|
|
32
|
+
// skipped at creation so SSR never touches IndexedDB).
|
|
33
|
+
//
|
|
34
|
+
// Both URL effects below wait on this flag, because the read is async and
|
|
35
|
+
// lands *after* the first commit: opening the deep-linked tab before it
|
|
36
|
+
// resolves means the restored snapshot's `activeParam` overwrites the tab the
|
|
37
|
+
// URL asked for, and the write-back then projects that wrong tab into the
|
|
38
|
+
// address bar. The URL is the more specific instruction, so it is applied
|
|
39
|
+
// once the store has finished restoring rather than before.
|
|
40
|
+
const [hydrated, setHydrated] = useState(false);
|
|
41
|
+
useEffect(()=>{
|
|
42
|
+
// The scope is applied *before* the read, not after: the storage key is what
|
|
43
|
+
// decides whose tabs and drafts come back, so setting it late would restore
|
|
44
|
+
// the unscoped set first and only then start writing to the right key. Both
|
|
45
|
+
// stores are module singletons with `skipHydration`, and this is the only
|
|
46
|
+
// place that rehydrates them, so re-pointing them here is enough — no store
|
|
47
|
+
// factory or provider is needed to keep two accounts apart.
|
|
48
|
+
useTabsState.persist.setOptions({
|
|
49
|
+
name: `tabs:${scope}`
|
|
50
|
+
});
|
|
51
|
+
useDraftsState.persist.setOptions({
|
|
52
|
+
name: `drafts:${scope}`
|
|
53
|
+
});
|
|
54
|
+
void Promise.all([
|
|
55
|
+
useTabsState.persist.rehydrate(),
|
|
56
|
+
useDraftsState.persist.rehydrate()
|
|
57
|
+
]).finally(()=>setHydrated(true));
|
|
58
|
+
}, [
|
|
59
|
+
scope
|
|
60
|
+
]);
|
|
61
|
+
// The `?tab=` value the registry cannot resolve, if any — derived, so it is
|
|
62
|
+
// known on the very first render rather than an effect later. An
|
|
63
|
+
// unresolvable address used to be dropped on the floor: no tab, no error,
|
|
64
|
+
// and the write-back below then replaced it with the previously active tab,
|
|
65
|
+
// so even the URL stopped saying what was asked for. Here it answers with
|
|
66
|
+
// the fallback and the bad address stays in the bar, where it can be read.
|
|
67
|
+
//
|
|
68
|
+
// `dismissed` is the escape: a deliberate tab interaction is a newer
|
|
69
|
+
// instruction than the address that failed, and it holds the *value* rather
|
|
70
|
+
// than a flag so the next dead link is dead again.
|
|
71
|
+
const [dismissed, setDismissed] = useState(null);
|
|
72
|
+
const deadLink = urlTab && urlTab !== dismissed && !registry.resolve(urlTab, translate) ? urlTab : null;
|
|
73
|
+
// A tab is dirty while its address has an unsaved draft; closing one confirms.
|
|
74
|
+
//
|
|
75
|
+
// The confirmation is a rendered dialog, so the decision spans two commits
|
|
76
|
+
// rather than one blocking call: `handleClose` either closes outright or
|
|
77
|
+
// parks the address, and the dialog's own buttons finish it. `window.confirm`
|
|
78
|
+
// could not be styled, blocked the thread while it was up, and in Playwright
|
|
79
|
+
// had to be driven by a global `page.on('dialog')` handler registered before
|
|
80
|
+
// the click — which is why the workspace had no end-to-end test at all.
|
|
81
|
+
const [pendingClose, setPendingClose] = useState(null);
|
|
82
|
+
const commitClose = (param)=>{
|
|
83
|
+
// Unconditional: `clearDraft` returns the state unchanged when the address
|
|
84
|
+
// holds no draft, so the clean path costs a no-op rather than a branch.
|
|
85
|
+
clearDraft(param);
|
|
86
|
+
setDismissed(urlTab);
|
|
87
|
+
close(param);
|
|
88
|
+
};
|
|
89
|
+
const handleClose = (param)=>{
|
|
90
|
+
if (param in drafts) {
|
|
91
|
+
setPendingClose(param);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
commitClose(param);
|
|
95
|
+
};
|
|
96
|
+
const handleActivate = (param)=>{
|
|
97
|
+
setDismissed(urlTab);
|
|
98
|
+
activate(param);
|
|
99
|
+
};
|
|
100
|
+
// Deep link → open/focus the addressed tab (a dead one shows the fallback).
|
|
101
|
+
useEffect(()=>{
|
|
102
|
+
if (!hydrated || !urlTab) return;
|
|
103
|
+
const resolved = registry.resolve(urlTab, translate);
|
|
104
|
+
if (resolved) {
|
|
105
|
+
open({
|
|
106
|
+
param: resolved.param,
|
|
107
|
+
title: resolved.title
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}, [
|
|
111
|
+
hydrated,
|
|
112
|
+
urlTab,
|
|
113
|
+
registry,
|
|
114
|
+
open,
|
|
115
|
+
translate
|
|
116
|
+
]);
|
|
117
|
+
// Project the active tab back to the URL so it stays shareable.
|
|
118
|
+
//
|
|
119
|
+
// The active tab is read from the *committed* store rather than from this
|
|
120
|
+
// render's snapshot. Following a link to a second tab changes the URL one
|
|
121
|
+
// commit before the store catches up, so the snapshot still names the
|
|
122
|
+
// previously active tab — writing that back would undo the navigation, the
|
|
123
|
+
// effect above would re-open the URL's tab, and the two would trade the
|
|
124
|
+
// address bar back and forth forever (a visible flicker between, say, brands
|
|
125
|
+
// and categories). The effect above runs first in the same commit, so by the
|
|
126
|
+
// time this one reads the store the URL's tab is already active.
|
|
127
|
+
// That ordering is also what makes the `hydrated` gate work: when the flag
|
|
128
|
+
// flips, the effect above has already re-applied the URL's tab over the
|
|
129
|
+
// restored snapshot, so there is nothing here to write back.
|
|
130
|
+
//
|
|
131
|
+
// A dead deep link suspends it: overwriting the address the visitor typed
|
|
132
|
+
// with an unrelated tab is what made the failure invisible in the first place.
|
|
133
|
+
useEffect(()=>{
|
|
134
|
+
if (!hydrated || deadLink) return;
|
|
135
|
+
const active = useTabsState.getState().activeParam;
|
|
136
|
+
if (active && active !== urlTab) {
|
|
137
|
+
router.replace(`${pathname}?tab=${encodeURIComponent(active)}`);
|
|
138
|
+
}
|
|
139
|
+
}, [
|
|
140
|
+
hydrated,
|
|
141
|
+
deadLink,
|
|
142
|
+
activeParam,
|
|
143
|
+
urlTab,
|
|
144
|
+
pathname,
|
|
145
|
+
router
|
|
146
|
+
]);
|
|
147
|
+
const copyDeepLink = (param)=>{
|
|
148
|
+
void navigator.clipboard.writeText(`${window.location.origin}${pathname}?tab=${encodeURIComponent(param)}`);
|
|
149
|
+
};
|
|
150
|
+
const activeResolved = activeParam ? registry.resolve(activeParam, translate) : null;
|
|
151
|
+
const body = deadLink ? fallback : activeResolved ? activeResolved.render() : emptyState;
|
|
152
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
153
|
+
className: "min-w-0 flex flex-1 flex-col",
|
|
154
|
+
children: [
|
|
155
|
+
/*#__PURE__*/ _jsx(TopBar, {
|
|
156
|
+
children: /*#__PURE__*/ _jsxs(TopBar.Actions, {
|
|
157
|
+
children: [
|
|
158
|
+
activeParam && /*#__PURE__*/ _jsx("button", {
|
|
159
|
+
type: "button",
|
|
160
|
+
onClick: ()=>copyDeepLink(activeParam),
|
|
161
|
+
className: "rounded-md px-2xs py-3xs text-step-sm text-content-muted focus-ring transition hover:bg-surface hover:text-content",
|
|
162
|
+
children: t('workspace.copyLink')
|
|
163
|
+
}),
|
|
164
|
+
actions
|
|
165
|
+
]
|
|
166
|
+
})
|
|
167
|
+
}),
|
|
168
|
+
/*#__PURE__*/ _jsx(TabStrip, {
|
|
169
|
+
children: tabs.map((tab)=>{
|
|
170
|
+
var _ref;
|
|
171
|
+
var _registry_resolve;
|
|
172
|
+
return /*#__PURE__*/ _jsx(Tab, {
|
|
173
|
+
// Re-derived from the registry rather than read back from the
|
|
174
|
+
// store: the persisted title is whatever locale it was opened
|
|
175
|
+
// in, so a locale switch would leave stale captions behind.
|
|
176
|
+
label: (_ref = (_registry_resolve = registry.resolve(tab.param, translate)) == null ? void 0 : _registry_resolve.title) != null ? _ref : tab.title,
|
|
177
|
+
// Nothing is selected while the fallback is up: a highlighted
|
|
178
|
+
// tab beside a body that is not its own reads as a render bug.
|
|
179
|
+
active: !deadLink && tab.param === activeParam,
|
|
180
|
+
state: tab.param in drafts ? 'dirty' : 'idle',
|
|
181
|
+
onSelect: ()=>handleActivate(tab.param),
|
|
182
|
+
onClose: ()=>handleClose(tab.param)
|
|
183
|
+
}, tab.param);
|
|
184
|
+
})
|
|
185
|
+
}),
|
|
186
|
+
/*#__PURE__*/ _jsx("div", {
|
|
187
|
+
className: "min-w-0 flex-1 p-m",
|
|
188
|
+
children: body
|
|
189
|
+
}),
|
|
190
|
+
pendingClose && /*#__PURE__*/ _jsx(ConfirmDialog, {
|
|
191
|
+
open: true,
|
|
192
|
+
tone: "destructive",
|
|
193
|
+
title: t('workspace.discardTitle'),
|
|
194
|
+
message: t('workspace.discard'),
|
|
195
|
+
confirmLabel: t('workspace.discardConfirm'),
|
|
196
|
+
onCancel: ()=>setPendingClose(null),
|
|
197
|
+
onConfirm: ()=>{
|
|
198
|
+
commitClose(pendingClose);
|
|
199
|
+
setPendingClose(null);
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
]
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
//# sourceMappingURL=workspace-shell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/workspace/workspace-shell.tsx"],"sourcesContent":["'use client';\n\nimport {\n ConfirmDialog,\n Tab,\n TabStrip,\n TopBar,\n useT,\n useTranslateKey,\n} from '@entifix/react-controls';\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation';\nimport { type ReactNode, useEffect, useState } from 'react';\n\nimport { useDraftsState } from './drafts-state.js';\nimport type { TabRegistry } from './tab-kind.js';\nimport { useTabsState } from './tabs-state.js';\n\nexport interface WorkspaceShellProps {\n /**\n * Who this workspace belongs to — `workspaceScopeKey({ userId,\n * organizationId })`, resolved on the server from the session.\n *\n * Required, deliberately: IndexedDB is a property of the browser profile, so a\n * host that forgets to pass one hands the next account to sign in on that\n * machine the previous account's open tabs and half-finished edits. A default\n * would make that the quiet outcome of doing nothing.\n */\n scope: string;\n /** Resolves `?tab=` values to renderable tabs. */\n registry: TabRegistry;\n /** Right-aligned actions above the tab strip (search, the user menu). */\n actions?: ReactNode;\n /** Body when `?tab=` names something the registry cannot resolve. */\n fallback?: ReactNode;\n /** Body when no tab is open. */\n emptyState?: ReactNode;\n}\n\n/**\n * The tab workspace: a strip of persisted tabs over the active tab's body — no\n * sidebar or brand of its own. It is mounted inside a host shell (the\n * back-office layout, say) that already supplies those, so nesting two\n * sidebars never happens. The open set lives in {@link useTabsState}\n * (IndexedDB); the URL's `?tab=` projects only the active tab, so a deep link\n * opens or focuses exactly that tab and an unknown kind shows the fallback\n * instead of crashing.\n */\nexport function WorkspaceShell({\n scope,\n registry,\n actions,\n fallback,\n emptyState,\n}: WorkspaceShellProps) {\n const t = useT('shell');\n // Tab captions are catalog keys carried in a registry, not authored copy.\n const translate = useTranslateKey();\n const searchParams = useSearchParams();\n const router = useRouter();\n const pathname = usePathname();\n const urlTab = searchParams.get('tab');\n\n const tabs = useTabsState(state => state.tabs);\n const activeParam = useTabsState(state => state.activeParam);\n const open = useTabsState(state => state.open);\n const close = useTabsState(state => state.close);\n const activate = useTabsState(state => state.activate);\n\n const drafts = useDraftsState(state => state.drafts);\n const clearDraft = useDraftsState(state => state.clearDraft);\n\n // Load the persisted tab set and drafts once, on the client (hydration is\n // skipped at creation so SSR never touches IndexedDB).\n //\n // Both URL effects below wait on this flag, because the read is async and\n // lands *after* the first commit: opening the deep-linked tab before it\n // resolves means the restored snapshot's `activeParam` overwrites the tab the\n // URL asked for, and the write-back then projects that wrong tab into the\n // address bar. The URL is the more specific instruction, so it is applied\n // once the store has finished restoring rather than before.\n const [hydrated, setHydrated] = useState(false);\n useEffect(() => {\n // The scope is applied *before* the read, not after: the storage key is what\n // decides whose tabs and drafts come back, so setting it late would restore\n // the unscoped set first and only then start writing to the right key. Both\n // stores are module singletons with `skipHydration`, and this is the only\n // place that rehydrates them, so re-pointing them here is enough — no store\n // factory or provider is needed to keep two accounts apart.\n useTabsState.persist.setOptions({ name: `tabs:${scope}` });\n useDraftsState.persist.setOptions({ name: `drafts:${scope}` });\n void Promise.all([\n useTabsState.persist.rehydrate(),\n useDraftsState.persist.rehydrate(),\n ]).finally(() => setHydrated(true));\n }, [scope]);\n\n // The `?tab=` value the registry cannot resolve, if any — derived, so it is\n // known on the very first render rather than an effect later. An\n // unresolvable address used to be dropped on the floor: no tab, no error,\n // and the write-back below then replaced it with the previously active tab,\n // so even the URL stopped saying what was asked for. Here it answers with\n // the fallback and the bad address stays in the bar, where it can be read.\n //\n // `dismissed` is the escape: a deliberate tab interaction is a newer\n // instruction than the address that failed, and it holds the *value* rather\n // than a flag so the next dead link is dead again.\n const [dismissed, setDismissed] = useState<string | null>(null);\n const deadLink =\n urlTab && urlTab !== dismissed && !registry.resolve(urlTab, translate)\n ? urlTab\n : null;\n\n // A tab is dirty while its address has an unsaved draft; closing one confirms.\n //\n // The confirmation is a rendered dialog, so the decision spans two commits\n // rather than one blocking call: `handleClose` either closes outright or\n // parks the address, and the dialog's own buttons finish it. `window.confirm`\n // could not be styled, blocked the thread while it was up, and in Playwright\n // had to be driven by a global `page.on('dialog')` handler registered before\n // the click — which is why the workspace had no end-to-end test at all.\n const [pendingClose, setPendingClose] = useState<string | null>(null);\n\n const commitClose = (param: string) => {\n // Unconditional: `clearDraft` returns the state unchanged when the address\n // holds no draft, so the clean path costs a no-op rather than a branch.\n clearDraft(param);\n setDismissed(urlTab);\n close(param);\n };\n\n const handleClose = (param: string) => {\n if (param in drafts) {\n setPendingClose(param);\n return;\n }\n commitClose(param);\n };\n\n const handleActivate = (param: string) => {\n setDismissed(urlTab);\n activate(param);\n };\n\n // Deep link → open/focus the addressed tab (a dead one shows the fallback).\n useEffect(() => {\n if (!hydrated || !urlTab) return;\n const resolved = registry.resolve(urlTab, translate);\n if (resolved) {\n open({ param: resolved.param, title: resolved.title });\n }\n }, [hydrated, urlTab, registry, open, translate]);\n\n // Project the active tab back to the URL so it stays shareable.\n //\n // The active tab is read from the *committed* store rather than from this\n // render's snapshot. Following a link to a second tab changes the URL one\n // commit before the store catches up, so the snapshot still names the\n // previously active tab — writing that back would undo the navigation, the\n // effect above would re-open the URL's tab, and the two would trade the\n // address bar back and forth forever (a visible flicker between, say, brands\n // and categories). The effect above runs first in the same commit, so by the\n // time this one reads the store the URL's tab is already active.\n // That ordering is also what makes the `hydrated` gate work: when the flag\n // flips, the effect above has already re-applied the URL's tab over the\n // restored snapshot, so there is nothing here to write back.\n //\n // A dead deep link suspends it: overwriting the address the visitor typed\n // with an unrelated tab is what made the failure invisible in the first place.\n useEffect(() => {\n if (!hydrated || deadLink) return;\n const active = useTabsState.getState().activeParam;\n if (active && active !== urlTab) {\n router.replace(`${pathname}?tab=${encodeURIComponent(active)}`);\n }\n }, [hydrated, deadLink, activeParam, urlTab, pathname, router]);\n\n const copyDeepLink = (param: string) => {\n void navigator.clipboard.writeText(\n `${window.location.origin}${pathname}?tab=${encodeURIComponent(param)}`,\n );\n };\n\n const activeResolved = activeParam\n ? registry.resolve(activeParam, translate)\n : null;\n const body = deadLink\n ? fallback\n : activeResolved\n ? activeResolved.render()\n : emptyState;\n\n return (\n <div className=\"min-w-0 flex flex-1 flex-col\">\n <TopBar>\n <TopBar.Actions>\n {activeParam && (\n <button\n type=\"button\"\n onClick={() => copyDeepLink(activeParam)}\n className=\"rounded-md px-2xs py-3xs text-step-sm text-content-muted focus-ring transition hover:bg-surface hover:text-content\"\n >\n {t('workspace.copyLink')}\n </button>\n )}\n {actions}\n </TopBar.Actions>\n </TopBar>\n\n <TabStrip>\n {tabs.map(tab => (\n <Tab\n key={tab.param}\n // Re-derived from the registry rather than read back from the\n // store: the persisted title is whatever locale it was opened\n // in, so a locale switch would leave stale captions behind.\n label={registry.resolve(tab.param, translate)?.title ?? tab.title}\n // Nothing is selected while the fallback is up: a highlighted\n // tab beside a body that is not its own reads as a render bug.\n active={!deadLink && tab.param === activeParam}\n state={tab.param in drafts ? 'dirty' : 'idle'}\n onSelect={() => handleActivate(tab.param)}\n onClose={() => handleClose(tab.param)}\n />\n ))}\n </TabStrip>\n\n <div className=\"min-w-0 flex-1 p-m\">{body}</div>\n\n {pendingClose && (\n <ConfirmDialog\n open\n tone=\"destructive\"\n title={t('workspace.discardTitle')}\n message={t('workspace.discard')}\n confirmLabel={t('workspace.discardConfirm')}\n onCancel={() => setPendingClose(null)}\n onConfirm={() => {\n commitClose(pendingClose);\n setPendingClose(null);\n }}\n />\n )}\n </div>\n );\n}\n"],"names":["ConfirmDialog","Tab","TabStrip","TopBar","useT","useTranslateKey","usePathname","useRouter","useSearchParams","useEffect","useState","useDraftsState","useTabsState","WorkspaceShell","scope","registry","actions","fallback","emptyState","t","translate","searchParams","router","pathname","urlTab","get","tabs","state","activeParam","open","close","activate","drafts","clearDraft","hydrated","setHydrated","persist","setOptions","name","Promise","all","rehydrate","finally","dismissed","setDismissed","deadLink","resolve","pendingClose","setPendingClose","commitClose","param","handleClose","handleActivate","resolved","title","active","getState","replace","encodeURIComponent","copyDeepLink","navigator","clipboard","writeText","window","location","origin","activeResolved","body","render","div","className","Actions","button","type","onClick","map","tab","label","onSelect","onClose","tone","message","confirmLabel","onCancel","onConfirm"],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from './lib/health/health-routes.js';
|
|
2
|
+
export * from './lib/config/config-route.js';
|
|
3
|
+
export * from './lib/config/service-token.js';
|
|
4
|
+
export * from './lib/config/service-proxy-route.js';
|
|
5
|
+
export * from './lib/session/cookies.js';
|
|
6
|
+
export * from './lib/session/refresh-route.js';
|
|
7
|
+
export * from './lib/crud/slug.js';
|
|
8
|
+
export * from './lib/search/record-search-route.js';
|
|
9
|
+
export * from './lib/search/record-search-source.js';
|
|
10
|
+
export * from './lib/session/bearer.js';
|
|
11
|
+
export * from './lib/session/account-links.js';
|
|
12
|
+
export * from './lib/session/device.js';
|
|
13
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAWA,cAAc,+BAA+B,CAAC;AAG9C,cAAc,8BAA8B,CAAC;AAM7C,cAAc,+BAA+B,CAAC;AAG9C,cAAc,qCAAqC,CAAC;AAGpD,cAAc,0BAA0B,CAAC;AACzC,cAAc,gCAAgC,CAAC;AAK/C,cAAc,oBAAoB,CAAC;AAInC,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AAKrD,cAAc,yBAAyB,CAAC;AAIxC,cAAc,gCAAgC,CAAC;AAG/C,cAAc,yBAAyB,CAAC"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Server-only surface, published as `@entifix/next-shell/server`.
|
|
2
|
+
//
|
|
3
|
+
// It stays a separate entry so route handlers and cookie helpers are never
|
|
4
|
+
// reached through the client surface: stamped as client modules they would
|
|
5
|
+
// become client references and their `next/server` imports would fail. The
|
|
6
|
+
// library compiles per-file, so each module keeps its own `"use client"` (or
|
|
7
|
+
// keeps none, as here) instead of inheriting a bundle-wide banner.
|
|
8
|
+
// React server components
|
|
9
|
+
// Probe route handlers (liveness/readiness) shared by every Next app.
|
|
10
|
+
export * from './lib/health/health-routes.js';
|
|
11
|
+
// The `GET /api/config` handler + the same-origin domain rewrite it applies.
|
|
12
|
+
export * from './lib/config/config-route.js';
|
|
13
|
+
// The shared fleet token, and the header config-service reads it from. Exported
|
|
14
|
+
// because a server component that reads config-service directly — rather than
|
|
15
|
+
// through its own app's `/api/config` route — has to carry it itself. It never
|
|
16
|
+
// reaches the browser: this is the server entry.
|
|
17
|
+
export * from './lib/config/service-token.js';
|
|
18
|
+
// The same-origin proxy each host mounts per backend it talks to.
|
|
19
|
+
export * from './lib/config/service-proxy-route.js';
|
|
20
|
+
// Session cookies + the shared refresh route handler
|
|
21
|
+
export * from './lib/session/cookies.js';
|
|
22
|
+
export * from './lib/session/refresh-route.js';
|
|
23
|
+
// The `[slug]` value that means "create". A pure constant, exported from both
|
|
24
|
+
// entries because both need it: the generated pages read it in the browser, and
|
|
25
|
+
// a shell's palette commands compose the create route with it on the server.
|
|
26
|
+
export * from './lib/crud/slug.js';
|
|
27
|
+
// The cross-domain record search: the aggregating route, and the declarations a
|
|
28
|
+
// host fans out over (ADR 0040).
|
|
29
|
+
export * from './lib/search/record-search-route.js';
|
|
30
|
+
export * from './lib/search/record-search-source.js';
|
|
31
|
+
// The access cookie, read once and forwarded as a bearer. Three server surfaces
|
|
32
|
+
// carry it the same way — the per-backend proxy, the auth shell's hand-written
|
|
33
|
+
// handlers, and the record search fan-out — and none of them grants anything.
|
|
34
|
+
export * from './lib/session/bearer.js';
|
|
35
|
+
// Account-link builders. Pure functions, but server layouts call them directly,
|
|
36
|
+
// and anything exported from the client entry becomes a client function.
|
|
37
|
+
export * from './lib/session/account-links.js';
|
|
38
|
+
// Device identity — read from the request, written onto the response.
|
|
39
|
+
export * from './lib/session/device.js';
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["// Server-only surface, published as `@entifix/next-shell/server`.\n//\n// It stays a separate entry so route handlers and cookie helpers are never\n// reached through the client surface: stamped as client modules they would\n// become client references and their `next/server` imports would fail. The\n// library compiles per-file, so each module keeps its own `\"use client\"` (or\n// keeps none, as here) instead of inheriting a bundle-wide banner.\n\n// React server components\n\n// Probe route handlers (liveness/readiness) shared by every Next app.\nexport * from './lib/health/health-routes.js';\n\n// The `GET /api/config` handler + the same-origin domain rewrite it applies.\nexport * from './lib/config/config-route.js';\n\n// The shared fleet token, and the header config-service reads it from. Exported\n// because a server component that reads config-service directly — rather than\n// through its own app's `/api/config` route — has to carry it itself. It never\n// reaches the browser: this is the server entry.\nexport * from './lib/config/service-token.js';\n\n// The same-origin proxy each host mounts per backend it talks to.\nexport * from './lib/config/service-proxy-route.js';\n\n// Session cookies + the shared refresh route handler\nexport * from './lib/session/cookies.js';\nexport * from './lib/session/refresh-route.js';\n\n// The `[slug]` value that means \"create\". A pure constant, exported from both\n// entries because both need it: the generated pages read it in the browser, and\n// a shell's palette commands compose the create route with it on the server.\nexport * from './lib/crud/slug.js';\n\n// The cross-domain record search: the aggregating route, and the declarations a\n// host fans out over (ADR 0040).\nexport * from './lib/search/record-search-route.js';\nexport * from './lib/search/record-search-source.js';\n\n// The access cookie, read once and forwarded as a bearer. Three server surfaces\n// carry it the same way — the per-backend proxy, the auth shell's hand-written\n// handlers, and the record search fan-out — and none of them grants anything.\nexport * from './lib/session/bearer.js';\n\n// Account-link builders. Pure functions, but server layouts call them directly,\n// and anything exported from the client entry becomes a client function.\nexport * from './lib/session/account-links.js';\n\n// Device identity — read from the request, written onto the response.\nexport * from './lib/session/device.js';\n"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,2EAA2E;AAC3E,6EAA6E;AAC7E,mEAAmE;AAEnE,0BAA0B;AAE1B,sEAAsE;AACtE,cAAc,gCAAgC;AAE9C,6EAA6E;AAC7E,cAAc,+BAA+B;AAE7C,gFAAgF;AAChF,8EAA8E;AAC9E,+EAA+E;AAC/E,iDAAiD;AACjD,cAAc,gCAAgC;AAE9C,kEAAkE;AAClE,cAAc,sCAAsC;AAEpD,qDAAqD;AACrD,cAAc,2BAA2B;AACzC,cAAc,iCAAiC;AAE/C,8EAA8E;AAC9E,gFAAgF;AAChF,6EAA6E;AAC7E,cAAc,qBAAqB;AAEnC,gFAAgF;AAChF,iCAAiC;AACjC,cAAc,sCAAsC;AACpD,cAAc,uCAAuC;AAErD,gFAAgF;AAChF,+EAA+E;AAC/E,8EAA8E;AAC9E,cAAc,0BAA0B;AAExC,gFAAgF;AAChF,yEAAyE;AACzE,cAAc,iCAAiC;AAE/C,sEAAsE;AACtE,cAAc,0BAA0B"}
|
package/package.json
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@entifix/next-shell",
|
|
3
|
+
"nx": {
|
|
4
|
+
"tags": [
|
|
5
|
+
"layer:shell",
|
|
6
|
+
"scope:shared",
|
|
7
|
+
"shell:base",
|
|
8
|
+
"tier:4"
|
|
9
|
+
],
|
|
10
|
+
"sourceRoot": "packages/next/shell/src",
|
|
11
|
+
"targets": {
|
|
12
|
+
"build": {
|
|
13
|
+
"executor": "@nx/js:swc",
|
|
14
|
+
"outputs": [
|
|
15
|
+
"{options.outputPath}"
|
|
16
|
+
],
|
|
17
|
+
"options": {
|
|
18
|
+
"outputPath": "packages/next/shell/dist",
|
|
19
|
+
"main": "packages/next/shell/src/index.ts",
|
|
20
|
+
"tsConfig": "packages/next/shell/tsconfig.lib.json",
|
|
21
|
+
"skipTypeCheck": true,
|
|
22
|
+
"stripLeadingPaths": true
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"version": "0.1.0-0",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/r10c-technologies/entifix.git",
|
|
32
|
+
"directory": "packages/next/shell"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"type": "module",
|
|
38
|
+
"main": "./dist/index.js",
|
|
39
|
+
"module": "./dist/index.js",
|
|
40
|
+
"types": "./dist/index.d.ts",
|
|
41
|
+
"exports": {
|
|
42
|
+
"./package.json": "./package.json",
|
|
43
|
+
".": {
|
|
44
|
+
"@entifix/source": "./src/index.ts",
|
|
45
|
+
"types": "./dist/index.d.ts",
|
|
46
|
+
"import": "./dist/index.js",
|
|
47
|
+
"default": "./dist/index.js"
|
|
48
|
+
},
|
|
49
|
+
"./server": {
|
|
50
|
+
"@entifix/source": "./src/server.ts",
|
|
51
|
+
"types": "./dist/server.d.ts",
|
|
52
|
+
"import": "./dist/server.js",
|
|
53
|
+
"default": "./dist/server.js"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@tanstack/react-query": "^5.101.4",
|
|
58
|
+
"effect": "3.22.1",
|
|
59
|
+
"i18next": "26.3.6",
|
|
60
|
+
"next": "16.2.10",
|
|
61
|
+
"react": "19.2.8",
|
|
62
|
+
"react-dom": "19.2.8",
|
|
63
|
+
"zustand": "^5.0.15",
|
|
64
|
+
"@entifix/testing-unit": "0.1.0-0"
|
|
65
|
+
},
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"idb": "^8.0.3",
|
|
68
|
+
"@entifix/authz": "0.1.0-0",
|
|
69
|
+
"@entifix/business": "0.1.0-0",
|
|
70
|
+
"@entifix/transactions": "0.1.0-0",
|
|
71
|
+
"@entifix/i18n": "0.1.0-0",
|
|
72
|
+
"@entifix/react-integration": "0.1.0-0",
|
|
73
|
+
"@entifix/react-controls": "0.1.0-0",
|
|
74
|
+
"@entifix/core": "0.1.0-0"
|
|
75
|
+
},
|
|
76
|
+
"files": [
|
|
77
|
+
"dist",
|
|
78
|
+
"!**/*.tsbuildinfo",
|
|
79
|
+
"LICENSE"
|
|
80
|
+
],
|
|
81
|
+
"peerDependencies": {
|
|
82
|
+
"@tanstack/react-query": ">=5.101 <6",
|
|
83
|
+
"effect": ">=3.22 <4",
|
|
84
|
+
"i18next": ">=26 <27",
|
|
85
|
+
"next": ">=16 <17",
|
|
86
|
+
"react": ">=19 <20",
|
|
87
|
+
"react-dom": ">=19 <20",
|
|
88
|
+
"zustand": ">=5 <6"
|
|
89
|
+
},
|
|
90
|
+
"peerDependenciesMeta": {
|
|
91
|
+
"i18next": {
|
|
92
|
+
"optional": true
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|