@contractspec/lib.example-shared-ui 6.0.6 → 6.0.7

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.
Files changed (81) hide show
  1. package/.turbo/turbo-build.log +90 -84
  2. package/AGENTS.md +43 -25
  3. package/README.md +63 -35
  4. package/dist/EvolutionDashboard.js +9 -9
  5. package/dist/EvolutionSidebar.js +15 -15
  6. package/dist/LocalDataIndicator.js +3 -3
  7. package/dist/MarkdownView.d.ts +0 -7
  8. package/dist/MarkdownView.js +76 -172
  9. package/dist/PersonalizationInsights.js +12 -12
  10. package/dist/SaveToStudioButton.js +2 -2
  11. package/dist/SpecDrivenTemplateShell.d.ts +1 -1
  12. package/dist/SpecDrivenTemplateShell.js +10 -10
  13. package/dist/SpecEditorPanel.js +3 -3
  14. package/dist/TemplateShell.js +10 -10
  15. package/dist/browser/EvolutionDashboard.js +9 -9
  16. package/dist/browser/EvolutionSidebar.js +15 -15
  17. package/dist/browser/LocalDataIndicator.js +3 -3
  18. package/dist/browser/MarkdownView.js +76 -172
  19. package/dist/browser/PersonalizationInsights.js +12 -12
  20. package/dist/browser/SaveToStudioButton.js +2 -2
  21. package/dist/browser/SpecDrivenTemplateShell.js +10 -10
  22. package/dist/browser/SpecEditorPanel.js +3 -3
  23. package/dist/browser/TemplateShell.js +10 -10
  24. package/dist/browser/hooks/index.js +29 -29
  25. package/dist/browser/index.js +193 -286
  26. package/dist/browser/lib/component-registry.js +1 -1
  27. package/dist/browser/markdown/formatPresentationName.js +9 -0
  28. package/dist/browser/markdown/useMarkdownPresentation.js +65 -0
  29. package/dist/hooks/index.d.ts +3 -3
  30. package/dist/hooks/index.js +29 -29
  31. package/dist/index.d.ts +12 -11
  32. package/dist/index.js +193 -286
  33. package/dist/lib/component-registry.js +1 -1
  34. package/dist/markdown/formatPresentationName.d.ts +1 -0
  35. package/dist/markdown/formatPresentationName.js +10 -0
  36. package/dist/markdown/useMarkdownPresentation.d.ts +21 -0
  37. package/dist/markdown/useMarkdownPresentation.js +66 -0
  38. package/dist/node/EvolutionDashboard.js +9 -9
  39. package/dist/node/EvolutionSidebar.js +15 -15
  40. package/dist/node/LocalDataIndicator.js +3 -3
  41. package/dist/node/MarkdownView.js +76 -172
  42. package/dist/node/PersonalizationInsights.js +12 -12
  43. package/dist/node/SaveToStudioButton.js +2 -2
  44. package/dist/node/SpecDrivenTemplateShell.js +10 -10
  45. package/dist/node/SpecEditorPanel.js +3 -3
  46. package/dist/node/TemplateShell.js +10 -10
  47. package/dist/node/hooks/index.js +29 -29
  48. package/dist/node/index.js +193 -286
  49. package/dist/node/lib/component-registry.js +1 -1
  50. package/dist/node/markdown/formatPresentationName.js +9 -0
  51. package/dist/node/markdown/useMarkdownPresentation.js +65 -0
  52. package/dist/utils/index.d.ts +1 -1
  53. package/package.json +38 -11
  54. package/src/EvolutionDashboard.tsx +415 -415
  55. package/src/EvolutionSidebar.tsx +245 -245
  56. package/src/LocalDataIndicator.tsx +28 -28
  57. package/src/MarkdownView.tsx +119 -372
  58. package/src/OverlayContextProvider.tsx +272 -272
  59. package/src/PersonalizationInsights.tsx +232 -232
  60. package/src/SaveToStudioButton.tsx +51 -51
  61. package/src/SpecDrivenTemplateShell.tsx +59 -59
  62. package/src/SpecEditorPanel.tsx +138 -138
  63. package/src/TemplateShell.tsx +50 -50
  64. package/src/bundles/ExampleTemplateBundle.ts +78 -78
  65. package/src/hooks/index.ts +3 -3
  66. package/src/hooks/useBehaviorTracking.ts +252 -252
  67. package/src/hooks/useEvolution.ts +437 -437
  68. package/src/hooks/useRegistryTemplates.ts +42 -42
  69. package/src/hooks/useSpecContent.ts +214 -214
  70. package/src/hooks/useWorkflowComposer.ts +567 -567
  71. package/src/index.ts +12 -11
  72. package/src/lib/component-registry.tsx +40 -40
  73. package/src/lib/runtime-context.tsx +31 -31
  74. package/src/lib/types.ts +57 -57
  75. package/src/markdown/formatPresentationName.ts +9 -0
  76. package/src/markdown/useMarkdownPresentation.ts +107 -0
  77. package/src/overlay-types.ts +15 -15
  78. package/src/utils/fetchPresentationData.ts +13 -13
  79. package/src/utils/generateSpecFromTemplate.ts +29 -29
  80. package/src/utils/index.ts +1 -1
  81. package/tsconfig.json +8 -8
@@ -1,24 +1,24 @@
1
- import type { ReactNode } from 'react';
2
1
  import {
3
- BundleProvider,
4
- BundleRenderer,
2
+ BundleProvider,
3
+ BundleRenderer,
5
4
  } from '@contractspec/lib.surface-runtime/react';
6
5
  import type { ResolvedSurfacePlan } from '@contractspec/lib.surface-runtime/runtime/resolve-bundle';
6
+ import type { ReactNode } from 'react';
7
7
  import { LocalDataIndicator } from './LocalDataIndicator';
8
8
  import {
9
- SaveToStudioButton,
10
- type SaveToStudioButtonProps,
9
+ SaveToStudioButton,
10
+ type SaveToStudioButtonProps,
11
11
  } from './SaveToStudioButton';
12
12
 
13
13
  export interface SpecDrivenTemplateShellProps {
14
- plan: ResolvedSurfacePlan;
15
- title: string;
16
- description?: string;
17
- sidebar?: ReactNode;
18
- actions?: ReactNode;
19
- children: ReactNode;
20
- showSaveAction?: boolean;
21
- saveProps?: SaveToStudioButtonProps;
14
+ plan: ResolvedSurfacePlan;
15
+ title: string;
16
+ description?: string;
17
+ sidebar?: ReactNode;
18
+ actions?: ReactNode;
19
+ children: ReactNode;
20
+ showSaveAction?: boolean;
21
+ saveProps?: SaveToStudioButtonProps;
22
22
  }
23
23
 
24
24
  /**
@@ -27,53 +27,53 @@ export interface SpecDrivenTemplateShellProps {
27
27
  * Requires @contractspec/lib.surface-runtime as peer dependency.
28
28
  */
29
29
  export function SpecDrivenTemplateShell({
30
- plan,
31
- title,
32
- description,
33
- sidebar,
34
- actions,
35
- showSaveAction = true,
36
- saveProps,
37
- children,
30
+ plan,
31
+ title,
32
+ description,
33
+ sidebar,
34
+ actions,
35
+ showSaveAction = true,
36
+ saveProps,
37
+ children,
38
38
  }: SpecDrivenTemplateShellProps) {
39
- const headerContent = (
40
- <header className="border-border bg-card rounded-2xl border p-6 shadow-sm">
41
- <div className="flex flex-wrap items-center justify-between gap-4">
42
- <div>
43
- <p className="text-muted-foreground text-sm font-semibold tracking-wide uppercase">
44
- ContractSpec Templates
45
- </p>
46
- <h1 className="text-3xl font-bold">{title}</h1>
47
- {description ? (
48
- <p className="text-muted-foreground mt-2 max-w-2xl text-sm">
49
- {description}
50
- </p>
51
- ) : null}
52
- </div>
53
- <div className="flex flex-col items-end gap-2">
54
- <LocalDataIndicator />
55
- {showSaveAction ? <SaveToStudioButton {...saveProps} /> : null}
56
- </div>
57
- </div>
58
- {actions ? <div className="mt-4">{actions}</div> : null}
59
- </header>
60
- );
39
+ const headerContent = (
40
+ <header className="rounded-2xl border border-border bg-card p-6 shadow-sm">
41
+ <div className="flex flex-wrap items-center justify-between gap-4">
42
+ <div>
43
+ <p className="font-semibold text-muted-foreground text-sm uppercase tracking-wide">
44
+ ContractSpec Templates
45
+ </p>
46
+ <h1 className="font-bold text-3xl">{title}</h1>
47
+ {description ? (
48
+ <p className="mt-2 max-w-2xl text-muted-foreground text-sm">
49
+ {description}
50
+ </p>
51
+ ) : null}
52
+ </div>
53
+ <div className="flex flex-col items-end gap-2">
54
+ <LocalDataIndicator />
55
+ {showSaveAction ? <SaveToStudioButton {...saveProps} /> : null}
56
+ </div>
57
+ </div>
58
+ {actions ? <div className="mt-4">{actions}</div> : null}
59
+ </header>
60
+ );
61
61
 
62
- const slotContent: Partial<Record<string, ReactNode>> = {
63
- header: headerContent,
64
- primary: <main className="space-y-4 p-2">{children}</main>,
65
- };
66
- if (sidebar != null) {
67
- slotContent.sidebar = (
68
- <aside className="border-border bg-card rounded-2xl border p-4">
69
- {sidebar}
70
- </aside>
71
- );
72
- }
62
+ const slotContent: Partial<Record<string, ReactNode>> = {
63
+ header: headerContent,
64
+ primary: <main className="space-y-4 p-2">{children}</main>,
65
+ };
66
+ if (sidebar != null) {
67
+ slotContent.sidebar = (
68
+ <aside className="rounded-2xl border border-border bg-card p-4">
69
+ {sidebar}
70
+ </aside>
71
+ );
72
+ }
73
73
 
74
- return (
75
- <BundleProvider plan={plan}>
76
- <BundleRenderer slotContent={slotContent} />
77
- </BundleProvider>
78
- );
74
+ return (
75
+ <BundleProvider plan={plan}>
76
+ <BundleRenderer slotContent={slotContent} />
77
+ </BundleProvider>
78
+ );
79
79
  }
@@ -1,27 +1,27 @@
1
1
  'use client';
2
2
 
3
- import { useCallback, useEffect } from 'react';
4
3
  import { Button, LoaderBlock } from '@contractspec/lib.design-system';
5
4
  import { Badge } from '@contractspec/lib.ui-kit-web/ui/badge';
6
- import type { TemplateId } from './lib/types';
5
+ import { useCallback, useEffect } from 'react';
7
6
  import { useSpecContent } from './hooks/useSpecContent';
7
+ import type { TemplateId } from './lib/types';
8
8
 
9
9
  export interface SpecEditorProps {
10
- projectId: string;
11
- type?: 'CAPABILITY' | 'DATAVIEW' | 'WORKFLOW' | 'POLICY' | 'COMPONENT';
12
- content: string;
13
- onChange: (content: string) => void;
14
- metadata?: Record<string, unknown>;
15
- onSave?: () => void;
16
- onValidate?: () => void;
10
+ projectId: string;
11
+ type?: 'CAPABILITY' | 'DATAVIEW' | 'WORKFLOW' | 'POLICY' | 'COMPONENT';
12
+ content: string;
13
+ onChange: (content: string) => void;
14
+ metadata?: Record<string, unknown>;
15
+ onSave?: () => void;
16
+ onValidate?: () => void;
17
17
  }
18
18
 
19
19
  export interface SpecEditorPanelProps {
20
- templateId: TemplateId;
21
- /** SpecEditor component passed as a prop (for dynamic import compatibility) */
22
- SpecEditor: React.ComponentType<SpecEditorProps>;
23
- /** Callback for logging actions */
24
- onLog?: (message: string) => void;
20
+ templateId: TemplateId;
21
+ /** SpecEditor component passed as a prop (for dynamic import compatibility) */
22
+ SpecEditor: React.ComponentType<SpecEditorProps>;
23
+ /** Callback for logging actions */
24
+ onLog?: (message: string) => void;
25
25
  }
26
26
 
27
27
  /**
@@ -29,137 +29,137 @@ export interface SpecEditorPanelProps {
29
29
  * Uses useSpecContent hook to manage spec persistence and validation.
30
30
  */
31
31
  export function SpecEditorPanel({
32
- templateId,
33
- SpecEditor,
34
- onLog,
32
+ templateId,
33
+ SpecEditor,
34
+ onLog,
35
35
  }: SpecEditorPanelProps) {
36
- const {
37
- content,
38
- loading,
39
- isDirty,
40
- validation,
41
- setContent,
42
- save,
43
- validate,
44
- reset,
45
- lastSaved,
46
- } = useSpecContent(templateId);
36
+ const {
37
+ content,
38
+ loading,
39
+ isDirty,
40
+ validation,
41
+ setContent,
42
+ save,
43
+ validate,
44
+ reset,
45
+ lastSaved,
46
+ } = useSpecContent(templateId);
47
47
 
48
- // Log when spec is loaded
49
- useEffect(() => {
50
- if (!loading && content) {
51
- onLog?.(`Spec loaded for ${templateId}`);
52
- }
53
- }, [loading, content, templateId, onLog]);
48
+ // Log when spec is loaded
49
+ useEffect(() => {
50
+ if (!loading && content) {
51
+ onLog?.(`Spec loaded for ${templateId}`);
52
+ }
53
+ }, [loading, content, templateId, onLog]);
54
54
 
55
- const handleSave = useCallback(() => {
56
- save();
57
- onLog?.('Spec saved locally');
58
- }, [save, onLog]);
55
+ const handleSave = useCallback(() => {
56
+ save();
57
+ onLog?.('Spec saved locally');
58
+ }, [save, onLog]);
59
59
 
60
- const handleValidate = useCallback(() => {
61
- const result = validate();
62
- if (result.valid) {
63
- onLog?.('Spec validation passed');
64
- } else {
65
- const errorCount = result.errors.filter(
66
- (e) => e.severity === 'error'
67
- ).length;
68
- const warnCount = result.errors.filter(
69
- (e) => e.severity === 'warning'
70
- ).length;
71
- onLog?.(`Spec validation: ${errorCount} errors, ${warnCount} warnings`);
72
- }
73
- }, [validate, onLog]);
60
+ const handleValidate = useCallback(() => {
61
+ const result = validate();
62
+ if (result.valid) {
63
+ onLog?.('Spec validation passed');
64
+ } else {
65
+ const errorCount = result.errors.filter(
66
+ (e) => e.severity === 'error'
67
+ ).length;
68
+ const warnCount = result.errors.filter(
69
+ (e) => e.severity === 'warning'
70
+ ).length;
71
+ onLog?.(`Spec validation: ${errorCount} errors, ${warnCount} warnings`);
72
+ }
73
+ }, [validate, onLog]);
74
74
 
75
- const handleReset = useCallback(() => {
76
- reset();
77
- onLog?.('Spec reset to template defaults');
78
- }, [reset, onLog]);
75
+ const handleReset = useCallback(() => {
76
+ reset();
77
+ onLog?.('Spec reset to template defaults');
78
+ }, [reset, onLog]);
79
79
 
80
- if (loading) {
81
- return <LoaderBlock label="Loading spec..." />;
82
- }
80
+ if (loading) {
81
+ return <LoaderBlock label="Loading spec..." />;
82
+ }
83
83
 
84
- return (
85
- <div className="space-y-4">
86
- {/* Spec Toolbar */}
87
- <div className="flex items-center justify-between">
88
- <div className="flex items-center gap-2">
89
- <Button variant="default" size="sm" onClick={handleSave}>
90
- Save
91
- </Button>
92
- <Button variant="outline" size="sm" onClick={handleValidate}>
93
- Validate
94
- </Button>
95
- {isDirty && (
96
- <Badge
97
- variant="secondary"
98
- className="border-amber-500/30 bg-amber-500/20 text-amber-400"
99
- >
100
- Unsaved changes
101
- </Badge>
102
- )}
103
- {validation && (
104
- <Badge
105
- variant={validation.valid ? 'default' : 'destructive'}
106
- className={
107
- validation.valid
108
- ? 'border-green-500/30 bg-green-500/20 text-green-400'
109
- : ''
110
- }
111
- >
112
- {validation.valid
113
- ? 'Valid'
114
- : `${validation.errors.filter((e) => e.severity === 'error').length} errors`}
115
- </Badge>
116
- )}
117
- </div>
118
- <div className="flex items-center gap-2">
119
- {lastSaved && (
120
- <span className="text-muted-foreground text-xs">
121
- Last saved: {new Date(lastSaved).toLocaleTimeString()}
122
- </span>
123
- )}
124
- <Button variant="ghost" size="sm" onPress={handleReset}>
125
- Reset
126
- </Button>
127
- </div>
128
- </div>
84
+ return (
85
+ <div className="space-y-4">
86
+ {/* Spec Toolbar */}
87
+ <div className="flex items-center justify-between">
88
+ <div className="flex items-center gap-2">
89
+ <Button variant="default" size="sm" onClick={handleSave}>
90
+ Save
91
+ </Button>
92
+ <Button variant="outline" size="sm" onClick={handleValidate}>
93
+ Validate
94
+ </Button>
95
+ {isDirty && (
96
+ <Badge
97
+ variant="secondary"
98
+ className="border-amber-500/30 bg-amber-500/20 text-amber-400"
99
+ >
100
+ Unsaved changes
101
+ </Badge>
102
+ )}
103
+ {validation && (
104
+ <Badge
105
+ variant={validation.valid ? 'default' : 'destructive'}
106
+ className={
107
+ validation.valid
108
+ ? 'border-green-500/30 bg-green-500/20 text-green-400'
109
+ : ''
110
+ }
111
+ >
112
+ {validation.valid
113
+ ? 'Valid'
114
+ : `${validation.errors.filter((e) => e.severity === 'error').length} errors`}
115
+ </Badge>
116
+ )}
117
+ </div>
118
+ <div className="flex items-center gap-2">
119
+ {lastSaved && (
120
+ <span className="text-muted-foreground text-xs">
121
+ Last saved: {new Date(lastSaved).toLocaleTimeString()}
122
+ </span>
123
+ )}
124
+ <Button variant="ghost" size="sm" onPress={handleReset}>
125
+ Reset
126
+ </Button>
127
+ </div>
128
+ </div>
129
129
 
130
- {/* Validation Errors */}
131
- {validation && validation.errors.length > 0 && (
132
- <div className="rounded-lg border border-amber-500/50 bg-amber-500/10 p-3">
133
- <p className="mb-2 text-xs font-semibold text-amber-400 uppercase">
134
- Validation Issues
135
- </p>
136
- <ul className="space-y-1">
137
- {validation.errors.map((error, index) => (
138
- <li
139
- key={`${error.line}-${error.message}-${index}`}
140
- className={`text-xs ${
141
- error.severity === 'error' ? 'text-red-400' : 'text-amber-400'
142
- }`}
143
- >
144
- Line {error.line}: {error.message}
145
- </li>
146
- ))}
147
- </ul>
148
- </div>
149
- )}
130
+ {/* Validation Errors */}
131
+ {validation && validation.errors.length > 0 && (
132
+ <div className="rounded-lg border border-amber-500/50 bg-amber-500/10 p-3">
133
+ <p className="mb-2 font-semibold text-amber-400 text-xs uppercase">
134
+ Validation Issues
135
+ </p>
136
+ <ul className="space-y-1">
137
+ {validation.errors.map((error, index) => (
138
+ <li
139
+ key={`${error.line}-${error.message}-${index}`}
140
+ className={`text-xs ${
141
+ error.severity === 'error' ? 'text-red-400' : 'text-amber-400'
142
+ }`}
143
+ >
144
+ Line {error.line}: {error.message}
145
+ </li>
146
+ ))}
147
+ </ul>
148
+ </div>
149
+ )}
150
150
 
151
- {/* Editor */}
152
- <div className="border-border bg-card rounded-2xl border p-4">
153
- <SpecEditor
154
- projectId="sandbox"
155
- type="CAPABILITY"
156
- content={content}
157
- onChange={setContent}
158
- metadata={{ template: templateId }}
159
- onSave={handleSave}
160
- onValidate={handleValidate}
161
- />
162
- </div>
163
- </div>
164
- );
151
+ {/* Editor */}
152
+ <div className="rounded-2xl border border-border bg-card p-4">
153
+ <SpecEditor
154
+ projectId="sandbox"
155
+ type="CAPABILITY"
156
+ content={content}
157
+ onChange={setContent}
158
+ metadata={{ template: templateId }}
159
+ onSave={handleSave}
160
+ onValidate={handleValidate}
161
+ />
162
+ </div>
163
+ </div>
164
+ );
165
165
  }
@@ -2,62 +2,62 @@ import type { ReactNode } from 'react';
2
2
 
3
3
  import { LocalDataIndicator } from './LocalDataIndicator';
4
4
  import {
5
- SaveToStudioButton,
6
- type SaveToStudioButtonProps,
5
+ SaveToStudioButton,
6
+ type SaveToStudioButtonProps,
7
7
  } from './SaveToStudioButton';
8
8
 
9
9
  export interface TemplateShellProps {
10
- title: string;
11
- description?: string;
12
- sidebar?: ReactNode;
13
- actions?: ReactNode;
14
- children: ReactNode;
15
- showSaveAction?: boolean;
16
- saveProps?: SaveToStudioButtonProps;
10
+ title: string;
11
+ description?: string;
12
+ sidebar?: ReactNode;
13
+ actions?: ReactNode;
14
+ children: ReactNode;
15
+ showSaveAction?: boolean;
16
+ saveProps?: SaveToStudioButtonProps;
17
17
  }
18
18
 
19
19
  export const TemplateShell = ({
20
- title,
21
- description,
22
- sidebar,
23
- actions,
24
- showSaveAction = true,
25
- saveProps,
26
- children,
20
+ title,
21
+ description,
22
+ sidebar,
23
+ actions,
24
+ showSaveAction = true,
25
+ saveProps,
26
+ children,
27
27
  }: TemplateShellProps) => (
28
- <div className="space-y-6">
29
- <header className="border-border bg-card rounded-2xl border p-6 shadow-sm">
30
- <div className="flex flex-wrap items-center justify-between gap-4">
31
- <div>
32
- <p className="text-muted-foreground text-sm font-semibold tracking-wide uppercase">
33
- ContractSpec Templates
34
- </p>
35
- <h1 className="text-3xl font-bold">{title}</h1>
36
- {description ? (
37
- <p className="text-muted-foreground mt-2 max-w-2xl text-sm">
38
- {description}
39
- </p>
40
- ) : null}
41
- </div>
42
- <div className="flex flex-col items-end gap-2">
43
- <LocalDataIndicator />
44
- {showSaveAction ? <SaveToStudioButton {...saveProps} /> : null}
45
- </div>
46
- </div>
47
- {actions ? <div className="mt-4">{actions}</div> : null}
48
- </header>
28
+ <div className="space-y-6">
29
+ <header className="rounded-2xl border border-border bg-card p-6 shadow-sm">
30
+ <div className="flex flex-wrap items-center justify-between gap-4">
31
+ <div>
32
+ <p className="font-semibold text-muted-foreground text-sm uppercase tracking-wide">
33
+ ContractSpec Templates
34
+ </p>
35
+ <h1 className="font-bold text-3xl">{title}</h1>
36
+ {description ? (
37
+ <p className="mt-2 max-w-2xl text-muted-foreground text-sm">
38
+ {description}
39
+ </p>
40
+ ) : null}
41
+ </div>
42
+ <div className="flex flex-col items-end gap-2">
43
+ <LocalDataIndicator />
44
+ {showSaveAction ? <SaveToStudioButton {...saveProps} /> : null}
45
+ </div>
46
+ </div>
47
+ {actions ? <div className="mt-4">{actions}</div> : null}
48
+ </header>
49
49
 
50
- <div
51
- className={
52
- sidebar ? 'grid gap-6 lg:grid-cols-[minmax(0,1fr)_320px]' : 'w-full'
53
- }
54
- >
55
- <main className="space-y-4 p-2">{children}</main>
56
- {sidebar ? (
57
- <aside className="border-border bg-card rounded-2xl border p-4">
58
- {sidebar}
59
- </aside>
60
- ) : null}
61
- </div>
62
- </div>
50
+ <div
51
+ className={
52
+ sidebar ? 'grid gap-6 lg:grid-cols-[minmax(0,1fr)_320px]' : 'w-full'
53
+ }
54
+ >
55
+ <main className="space-y-4 p-2">{children}</main>
56
+ {sidebar ? (
57
+ <aside className="rounded-2xl border border-border bg-card p-4">
58
+ {sidebar}
59
+ </aside>
60
+ ) : null}
61
+ </div>
62
+ </div>
63
63
  );