---
# System prepended metadata

title: Native Framework v2
tags: [native]

---

---
tags: native
---

# Native Framework v2

This is just documenting proposed changes to the fluentui-react-native control framework.

## Overall Approach

I wrapped the current framework in a library called @fluentui-react-native/framework.

- Includes: theming-react-native, theming-ramp, foundation-composable, foundation-compose, foundation-settings, foundation-tokens, themed-settings, immutable-merge, memo-cache, theme-registry
- I used Gulnaz's in-progress changes to get webpack bundle analyzer running for this to assess the size
- Not currently used in the code

Then I'm creating new things under `packages/experiments` in the repo as well as creating a new framework `@fluentui-react-native/experimental-framework`.

- This includes: theming-react-native, theming-ramp, foundation-settings, immutable-merge, memo-cache, theme-registry
- It reworks the tokens, themed-settings, composable and compose
- Bundle sizes are:

| Package | Stat | Parsed | Zipped |
| --- | --- | --- | --- |
| Normal | 89.42 KB | 34.33 KB | 8.56 KB |
| Experimental | 59.5 KB (66%) | 25.3 KB (73%) | 6.21 KB (72%) |

Note that the theming portions are more than half of the framework size so the reductions are more substantial than they seem.

## Goals

- Align things better with web
- Simplify the framework
- Reduce the bundle size to make it small and light.

## Proposed Changes

Note that these require knowledge of the existing native framework to provide the ncessary context. In progress changes can be seen at: https://github.com/JasonVMo/fluentui-react-native/tree/stack-fixes/packages/experimental/use-styling

### Simpler useStyling

I created an actual @fluentui-react-native/use-styling package. This allows for direct usage of the styling hook without the compose framework. It has the following changes:

#### TLDR

```ts
import { buildUseStyling } from `@fluentui-react-native/use-styling`;

const useStyling = buildUseStyling<Props, SlotProps, Tokens>({
  tokens: {
    // my tokens
  },
  styles: {
    root: styleFunction((tokens, theme) => {
      // same type of implementation
    }, ['token1', 'token2']);
    slot1: {
      style: {
        // these never really change
      }
    }
  },
  // which props are also tokens (or false for none, true for all)
  tokenProps: ['token1']
})
```

#### Only tokens are allowed as settings

Instead of:

```ts
settings: {
  tokens: { },
  root: {
    style: {}
  },
  slot1: {}
  _precedence: [],
  _overrides: {
    hover: {
      // repeat the same form
    }
  }
}
```

It is just tokens with layering

```ts
tokens: {
  backgroundColor: 'black',
  color: 'white',
  precedence: ['hover', 'press'],
  layers: {
    hover: {
      backgroundColor: 'gray'
    },
    press: {
    
    }
  }
}
```

Alternate Option:

```ts
tokens: {
  // stuff here
  hover: {
  
  },
  press: {
  
  }
},
precedence: ['hover', 'press'];
```

Some notes:

- same repeating pattern as before, just with a simpler data structure
- names are easy to change and up for discussion
- can also be a lookup into a theme, or a (theme) => Tokens function

#### Eventual plan for CSS vars

Adding a quick note for what hasn't hit the branch yet. Effectively tokens can be authored as:

```ts
tokens: {
  backgroundColor: Var('palette.neutralBackground', 'white'),
  color: Var('button.foregroundColor', Var('palette.neutralForeground', black))
}
```

If CSS vars are enabled this turns into:
```
tokens: {
  backgroundColor: 'var(--palette-neutralBackground, white)',
  color: 'var(--button-foregroundColor, var(--palette-neutralForeground, black))',
}
```

This ends up being a pure object with no theme dependency. As a result the component can be smart enough to know that it has no direct theme dependencies (outside of variables) and not even need to generate a theme specific class.

If CSS vars are not enabled (or on native):

- because the object contains functions it is wrapped in a theme => function
- styles and lookup results will be resolved against the theme

In essence an object has no dependencies whereas a theme function has a theme dependency. This can lead to some smart optimizations.


#### Styles are produced with functions or objects

No more magic arrays, in fact it is just a single function with the caching handled internal to the function.

- `styleFunction` has the same syntax and still works
- can write (tokens, theme, cache) => props (or just tokens => props) if desired yourself
- can also just provide props as an object

#### Other Notes

- How tokens and props overlap can be declared, this will patch tokens passed into props/style creation. This also allows for paring down of style functions.
- Usage is basically the same as before
- I removed all the root as special code, name your slots whatever you want 

### useSlots as a package

The functionality to consume/take-advantage of slot compression, to wrap slot rendering, to store the closures in state, and to encapsulate a styling solution (or not) is in a package.

Work in-progress: https://github.com/JasonVMo/fluentui-react-native/tree/stack-fixes/packages/experimental/use-slots

Usage looks like:

```tsx
/** @jsx withSlots */
import { withSlots, buildUseSlots } from '@fluentui-react-native/use-slots';

const useSlots = buildUseSlots<SlotProps>({
  slots: {
    container: View,
    content: Text
  },
  filters: {
    container: filterViewProps
  },
  useStyling = myUseStylingHook,
})

const Component = props => {
  const Slots = useSlots(props /* params are forwarded to useStyling */);
  const Content = Slots.content;
  return (
    <Slots.container {...props}>
      <Content>Hello World</Content>
    </Slots.container>
  )
}

```

The useStyling option can really be anything in the internal implementation. The exposure in the experimental-framework package is more opinionated.

### usePrepareProps + render become a single two-stage function

Composable breaks render into two stages, this allows for:

- stage1 to run hooks and load styling
- stage2 to render the JSX tree

This allows layer compression as a component written this way can be called safely as a function, rather than wrapping in createElement. The current system works but has a few weaknesses:

- It is a bit harder to understand
- Passing data between the functions is hard and requires things like a declared state

In the new pattern a staged component is one that can return a function component. This allows the second stage to be returned as a closure which can have arbitrary arguments passed in. The pattern looks like:

```ts

const MyButton = (props: ButtonProps) => {
  const [state, setState] = useButtonState(props)
  // lookup function to see if a state is applied, same as in useStyling now
  const hasLayer = layer => state.info[layer] || props[layer];
  // this will make the styling calls building prefab/themed styling into the slots
  const Slots = useSlots(props, hasLayer);
  
  // returned closure to finish off render
  return (extra: ButtonProps) => {
    const merged = mergeProps(props, extra);
    const hasIcon = merged.icon || state.icon;
    return (
      <Slots.root {...merged}>
        (hasIcon && <Slots.icon source={merged.icon} />)
        <Slots.content>merged.content</Slots.content>
      </Slots.root>
    )
  }
}

```

The hardest part of this is understanding when the props will come through. This is an issue in the current design as well. Generally passed in props will come through in part1, but props that are injected into the JSX will come in part2. In particular children.

Code: https://github.com/JasonVMo/fluentui-react-native/tree/stack-fixes/packages/experimental/composition

### Putting it all together

Ultimately things will look pretty similar to now, with compose things will look like:

```ts
const MyComp = compose<CompType>({
  displayName: 'MyComp',
  slots: {
    root: View,
    content: Text
  },
  tokens: [{
    // tokens
  }, 'MyComp' /* Theme lookup name */],
  styles: {
    root: styleFunction...
    content: styleFunction...
  },
  render: (props, useSlots) => {
    const Slots = useSlots(props);
    return (extra) => {
      
    }
  }
})
```

It will build the styling and slots out of the settings, wrap the staged function and build a customizable/composable component.

### Role of the framework package

The lower level libraries are fairly generic, they allow injecting of a theming system. In the experimental framework I'm re-exporting things with typed versions, that way consumers of the framework use typed functions whereas the libraries are still available if someone wants to use them individually.