From 8fcf7cf732b7394c3414caf266996c2ed7898e82 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr>
Date: Sun, 10 Jan 2021 15:15:54 +0100
Subject: [PATCH] [ivette] move LabView API in ivette

---
 ivette/src/ivette/index.tsx         | 173 +++++++++++++++++++++++++++
 ivette/src/renderer/Application.tsx |   3 +-
 ivette/src/renderer/LabView.tsx     | 176 +++-------------------------
 ivette/tsconfig.json                |   3 +-
 ivette/webpack.renderer.js          |   3 +-
 5 files changed, 194 insertions(+), 164 deletions(-)
 create mode 100644 ivette/src/ivette/index.tsx

diff --git a/ivette/src/ivette/index.tsx b/ivette/src/ivette/index.tsx
new file mode 100644
index 00000000000..e51739eedcd
--- /dev/null
+++ b/ivette/src/ivette/index.tsx
@@ -0,0 +1,173 @@
+// --------------------------------------------------------------------------
+// ---  Lab View Component
+// --------------------------------------------------------------------------
+
+/**
+   @packageDocumentation
+   @module ivette
+ */
+
+import React from 'react';
+import { Label } from 'dome/controls/labels';
+import { DefineElement } from 'dome/layout/dispatch';
+import {
+  Rankify,
+  useGroupContext,
+  useLibraryItem,
+  useTitleContext,
+} from 'ivette@lab';
+
+/* --------------------------------------------------------------------------*/
+/* --- Fragments                                                          ---*/
+/* --------------------------------------------------------------------------*/
+
+export interface FragmentProps {
+  group?: string;
+  rank?: number;
+  children?: React.ReactNode;
+}
+
+/**
+   Ordered collection of LabView Components.
+   Otherwise, elements are ordered by `rank` and `id`.
+ */
+export function Fragment(props: FragmentProps) {
+  const { group, rank, children } = props;
+  const context = useGroupContext();
+  const base = context.order ?? [];
+  return (
+    <Rankify
+      group={group ?? context.group}
+      order={rank === undefined ? base : [...base, rank]}
+    >
+      {children}
+    </Rankify>
+  );
+}
+
+/* --------------------------------------------------------------------------*/
+/* --- Groups                                                             ---*/
+/* --------------------------------------------------------------------------*/
+
+export interface ItemProps {
+  /** Identifier. */
+  id: string;
+  /** Displayed name. */
+  label: string;
+  /** Tooltip description. */
+  title?: string;
+  /** Contents. */
+  children?: React.ReactNode;
+}
+
+/**
+   Defines a group of components. The components rendered
+   _inside_ its content are implicitely affected to this group,
+   unless specified. The group content are also rendered
+   in their specified order. For nested collections of components,
+   use `<Fragment/>` instead of `<React.Fragment/>` to specify order.
+ */
+export function Group(props: ItemProps) {
+  const { children, ...group } = props;
+  const context = useLibraryItem('groups', group);
+  return (
+    <Rankify
+      group={props.id}
+      order={context.order ?? []}
+    >
+      {children}
+    </Rankify>
+  );
+}
+
+// --------------------------------------------------------------------------
+// --- Views
+// --------------------------------------------------------------------------
+
+export interface ViewProps extends ItemProps {
+  /** Use this view by default. */
+  defaultView?: boolean;
+}
+
+/**
+   Layout of LabView Components.
+   Defines a predefined layout of components. The view is organized
+   into a GridContent, which must _only_ consists of:
+   - `<GridHbox>…</GridHbox>` an horizontal grid of `GridContent` elements;
+   - `<GridVbox>…</GridVbox>` a vertical grid of `GridContent` elements;
+   - `<GridItem id=…>` a single component.
+
+   These grid content components must be imported from the `dome/layout/grids`
+   module:
+   ```
+   import { GridItem, GridHbox, GridVbox } from 'dome/layout/grids';
+   ```
+ */
+export function View(props: ViewProps) {
+  useLibraryItem('views', props);
+  return null;
+}
+
+// --------------------------------------------------------------------------
+// --- Components
+// --------------------------------------------------------------------------
+
+export interface ComponentProps extends ItemProps {
+  /** Group attachment (defaults to group context) */
+  group?: string;
+  /** Ordering index (defaults to fragment context). */
+  rank?: number;
+}
+
+/**
+   LabView Component.
+   Defines a component and its content when incorporated inside a view.
+   Unless specified, the component will be implicitely attached
+   to the current enclosing group. The `rank` property can be used
+   for adjusting component ordering (see also `<Fragment/>` and `<Group/>`).
+ */
+export function Component(props: ComponentProps) {
+  useLibraryItem('components', props);
+  return null;
+}
+
+export interface TitleBarProps {
+  /*
+     @property {string} [icon] - displayed icon
+     @property {string} [label] - displayed name
+     @property {string} [title] - description tooltip
+     @property {React.Children} children - additional components to render
+   */
+  /** Displayed icon. */
+  icon?: string;
+  /** Displayed name (when mounted). */
+  label?: string;
+  /** Tooltip description (when mounted). */
+  title?: string;
+  /** TitleBar additional components (stacked to right). */
+  children?: React.ReactNode;
+}
+
+/**
+   LabView Component's title bar.
+   Defines an alternative component title bar in current context.
+   Default values are taken from the associated component.
+ */
+export function TitleBar(props: TitleBarProps) {
+  const { icon, label, title, children } = props;
+  const context = useTitleContext();
+  if (!context.id) return null;
+  return (
+    <DefineElement id={`labview.title.${context.id}`}>
+      <Label
+        className="labview-handle"
+        icon={icon}
+        label={label || context.label}
+        title={title || context.title}
+      />
+      {children}
+    </DefineElement>
+  );
+}
+
+// --------------------------------------------------------------------------
diff --git a/ivette/src/renderer/Application.tsx b/ivette/src/renderer/Application.tsx
index 39f1c56396c..46f82f8a42b 100644
--- a/ivette/src/renderer/Application.tsx
+++ b/ivette/src/renderer/Application.tsx
@@ -15,7 +15,8 @@ import { GridHbox, GridItem } from 'dome/layout/grids';
 
 // --- Frama-C Plugins
 
-import { LabView, View, Group } from 'ivette';
+import { LabView } from 'ivette@lab';
+import { View, Group } from 'ivette';
 import Values from 'frama-c/eva/Values';
 import Dive from 'frama-c/dive/Dive';
 
diff --git a/ivette/src/renderer/LabView.tsx b/ivette/src/renderer/LabView.tsx
index dcd5f2a8457..ec68ab541ca 100644
--- a/ivette/src/renderer/LabView.tsx
+++ b/ivette/src/renderer/LabView.tsx
@@ -2,11 +2,6 @@
 // ---  Lab View Component
 // --------------------------------------------------------------------------
 
-/**
-   @packageDocumentation
-   @module ivette
-*/
-
 import _ from 'lodash';
 import React from 'react';
 import * as Dome from 'dome';
@@ -21,7 +16,7 @@ import { Hbox, Hfill, Vfill } from 'dome/layout/boxes';
 import { IconButton, Field } from 'dome/controls/buttons';
 import { Label } from 'dome/controls/labels';
 import { Icon } from 'dome/controls/icons';
-import { DefineElement, RenderElement } from 'dome/layout/dispatch';
+import { RenderElement } from 'dome/layout/dispatch';
 
 import './style-labview.css';
 
@@ -125,7 +120,14 @@ interface GroupContext {
 
 const GROUP = React.createContext<GroupContext>({});
 
-function useLibraryItem(fd: string, { id, ...props }: any): GroupContext {
+export function useGroupContext() {
+  return React.useContext(GROUP);
+}
+
+export function useLibraryItem(
+  fd: string,
+  { id, ...props }: any,
+): GroupContext {
   const context = React.useContext(GROUP);
   React.useEffect(() => {
     const { group, order } = context;
@@ -140,13 +142,13 @@ function useLibraryItem(fd: string, { id, ...props }: any): GroupContext {
 /* --- Rankifyier                                                         ---*/
 /* --------------------------------------------------------------------------*/
 
-interface RankifyProps {
+export interface RankifyProps {
   group: string | undefined;
   order: number[] | undefined;
   children: React.ReactNode | undefined;
 }
 
-function Rankify(props: RankifyProps) {
+export function Rankify(props: RankifyProps) {
   const { group, order = [], children } = props;
   let rank = 0;
   const rankify = (elt: any) => {
@@ -174,170 +176,22 @@ function UseLibrary(props: { children?: React.ReactNode }) {
   );
 }
 
-/* --------------------------------------------------------------------------*/
-/* --- Fragments                                                          ---*/
-/* --------------------------------------------------------------------------*/
-
-export interface FragmentProps {
-  group?: string;
-  rank?: number;
-  children?: React.ReactNode;
-}
-
-/**
-   Ordered collection of LabView Components.
-   Otherwise, elements are ordered by `rank` and `id`.
- */
-export function Fragment(props: FragmentProps) {
-  const { group, rank, children } = props;
-  const context = React.useContext(GROUP);
-  const base = context.order ?? [];
-  return (
-    <Rankify
-      group={group ?? context.group}
-      order={rank === undefined ? base : [...base, rank]}
-    >
-      {children}
-    </Rankify>
-  );
-}
-
-/* --------------------------------------------------------------------------*/
-/* --- Groups                                                             ---*/
-/* --------------------------------------------------------------------------*/
-
-export interface ItemProps {
-  /** Identifier. */
-  id: string;
-  /** Displayed name. */
-  label: string;
-  /** Tooltip description. */
-  title?: string;
-  /** Contents. */
-  children?: React.ReactNode;
-}
-
-/**
-   Defines a group of components. The components rendered
-   _inside_ its content are implicitely affected to this group,
-   unless specified. The group content are also rendered
-   in their specified order. For nested collections of components,
-   use `<Fragment/>` instead of `<React.Fragment/>` to specify order.
- */
-export function Group(props: ItemProps) {
-  const { children, ...group } = props;
-  const context = useLibraryItem('groups', group);
-  return (
-    <Rankify
-      group={props.id}
-      order={context.order ?? []}
-    >
-      {children}
-    </Rankify>
-  );
-}
-
 // --------------------------------------------------------------------------
-// --- Views
-// --------------------------------------------------------------------------
-
-export interface ViewProps extends ItemProps {
-  /** Use this view by default. */
-  defaultView?: boolean;
-}
-
-/**
-   Layout of LabView Components.
-   Defines a predefined layout of components. The view is organized
-   into a GridContent, which must _only_ consists of:
-   - `<GridHbox>…</GridHbox>` an horizontal grid of `GridContent` elements;
-   - `<GridVbox>…</GridVbox>` a vertical grid of `GridContent` elements;
-   - `<GridItem id=…>` a single component.
-
-   These grid content components must be imported from the `dome/layout/grids`
-   module:
-   ```
-   import { GridItem, GridHbox, GridVbox } from 'dome/layout/grids';
-   ```
- */
-export function View(props: ViewProps) {
-  useLibraryItem('views', props);
-  return null;
-}
-
-// --------------------------------------------------------------------------
-// --- Components
+// --- Grid Item
 // --------------------------------------------------------------------------
 
-export interface ComponentProps extends ItemProps {
-  /** Group attachment (defaults to group context) */
-  group?: string;
-  /** Ordering index (defaults to fragment context). */
-  rank?: number;
-}
-
-/**
-   LabView Component.
-   Defines a component and its content when incorporated inside a view.
-   Unless specified, the component will be implicitely attached
-   to the current enclosing group. The `rank` property can be used
-   for adjusting component ordering (see also `<Fragment/>` and `<Group/>`).
- */
-export function Component(props: ComponentProps) {
-  useLibraryItem('components', props);
-  return null;
-}
-
 interface TitleContext {
   id?: string;
   label?: string;
   title?: string;
 }
+
 const TITLE = React.createContext<TitleContext>({});
 
-export interface TitleBarProps {
-  /*
-     @property {string} [icon] - displayed icon
-     @property {string} [label] - displayed name
-     @property {string} [title] - description tooltip
-     @property {React.Children} children - additional components to render
-   */
-  /** Displayed icon. */
-  icon?: string;
-  /** Displayed name (when mounted). */
-  label?: string;
-  /** Tooltip description (when mounted). */
-  title?: string;
-  /** TitleBar additional components (stacked to right). */
-  children?: React.ReactNode;
+export function useTitleContext() {
+  return React.useContext(TITLE);
 }
 
-/**
-   LabView Component's title bar.
-   Defines an alternative component title bar in current context.
-   Default values are taken from the associated component.
- */
-export const TitleBar = ({ icon, label, title, children }: any) => {
-  const context = React.useContext(TITLE);
-  const { id } = context;
-  if (!id) return null;
-  return (
-    <DefineElement id={`labview.title.${id}`}>
-      <Label
-        className="labview-handle"
-        icon={icon}
-        label={label || context.label}
-        title={title || context.title}
-      />
-      {children}
-    </DefineElement>
-  );
-};
-
-// --------------------------------------------------------------------------
-// --- Grid Item
-// --------------------------------------------------------------------------
-
 const GRIDITEM = {
   className: 'dome-container dome-xBoxes-vbox dome-xBoxes-box',
   handle: '.labview-handle',
diff --git a/ivette/tsconfig.json b/ivette/tsconfig.json
index 6107a85a5aa..3258d0eb1e0 100644
--- a/ivette/tsconfig.json
+++ b/ivette/tsconfig.json
@@ -43,7 +43,8 @@
     "resolveJsonModule": true,                /* Allow to load JSON files as module. */
     "baseUrl": ".",                           /* Base directory to resolve non-absolute module names. */
     "paths": {                                /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
-      "ivette": [ "src/renderer/LabView.tsx" ],
+      "ivette@lab": [ "src/renderer/LabView.tsx" ],
+      "ivette": [ "src/ivette" ],
       "frama-c/api/*": [ "api/generated/*" ],
       "frama-c/*": [ "src/frama-c/*" ],
       "dome": [ "src/dome/renderer/dome.tsx" ],
diff --git a/ivette/webpack.renderer.js b/ivette/webpack.renderer.js
index 515c836cde5..0f02136b60b 100644
--- a/ivette/webpack.renderer.js
+++ b/ivette/webpack.renderer.js
@@ -29,7 +29,8 @@ module.exports = {
     alias: {
       'frama-c/api':  path.resolve( __dirname , 'api/generated' ),
       'frama-c':      path.resolve( __dirname , 'src/frama-c' ),
-      'ivette':       path.resolve( __dirname , 'src/renderer/LabView' ),
+      'ivette@lab':   path.resolve( __dirname , 'src/renderer/LabView' ),
+      'ivette':       path.resolve( __dirname , 'src/ivette' ),
       'dome/misc':    path.resolve( DOME , 'misc' ),
       'dome/system':  path.resolve( DOME , 'misc/system.ts' ),
       'dome$':        path.resolve( DOME , 'renderer/dome.tsx' ),
-- 
GitLab