Storyteller
Storyteller is a library for the discovery and rendering of UI stories and powers our storybook plugin Flipbook.
The API for this package focuses around the following areas:
- Validation for the Story format and Storybook format
- Discvoery of valid ModuleScripts with
.story
and.storybook
extensions - Loading of Stories and Storybooks into a sandbox with cacheless module requiring
- Rendering stories into a container with lifecycle callbacks for updating and unmounting
There also exist React hooks for ease of integration into storybook apps.
Functions
loadStoryModule
StoryModule LoadingLoads the source of a Story module.
A ModuleLoader instance is required for handling the requiring of the module.
This function will throw if the return value of storyModule
does not
conform to the Story format, or if the source
has a syntax error that require
would normally fail for.
For legacy compatibility this function also loads Hoarcekat
stories. Instead of a usual table-based Story definition, it takes the
returned function and wraps it in a Story, making the story
field the
function body.
isStorybookModule
ValidationStorybookValidates a given Instance is a Storybook module.
No validation is performed on the internals of the module. Only name and class are checked.
See Storyteller.loadStorybookModule for validation of the module source.
isStoryModule
ValidationStoryValidates a given Instance is a Story.
No validation is performed on the internals of the module. Only name and class are checked.
See Storyteller.loadStoryModule for validation of the module source.
loadStorybookModule
StorybookModule LoadingStoryteller.
loadStorybookModule
(
providedLoader:
ModuleLoader?
) →
LoadedStorybook
Loads the source of a Storybook module.
A ModuleLoader instance is required for handling the requiring of the module.
This function will throw if the return value of storybookModule
does not
conform to Storybook format, or if the
source has a syntax error that require
would normally fail for.
findStoryModulesForStorybook
StorybookStoryDiscoveryDiscovers all Story modules that are managed by the given Storybook.
render
RenderingRender a Story to an Instance in the DataModel.
After discovering, validating, and loading Story modules, rendering them is the final step to getting stories visually presented to the user.
This function handles the lifecycle of mounting, updating, and unmounting the Story. On each update controls can be passed down to the story for live-reloading from user interaction.
Usage:
local ModuleLoader = require("@pkg/ModuleLoader")
local Storyteller = require("@pkg/Storyteller")
-- At least one `.storybook` module must be present
local storybookModules = Storyteller.findStorybookModules(game)
assert(#storybookModules > 0, "no Storybook modules found")
local storybook
pcall(function()
storybook = Storyteller.loadStorybookModule(storybookModules[1])
end)
if storybook then
-- At least one `.story` module must be a descendant of the Instances in
-- a Storybook's `storyRoots` array
local storyModules = Storyteller.findStoryModulesForStorybook(storybook)
assert(#storyModules > 0, "no Story modules found")
local story
pcall(function()
story = Storyteller.loadStoryModule(storyModules[1], storybook)
end)
if story then
-- Finally, render the story to a container of your choosing
local lifecycle = Storyteller.render(container, story)
print(container:GetChildren())
lifecycle.unmount()
print(container:GetChildren())
end
end
useStory
ReactStoryStoryteller.
useStory
(
storybook:
types.LoadedStorybook
) →
(
types.LoadedStory
<
unknown
>
?
,
string?
)
This hook triggers a rerender when the Story module or any of its required
modules change. For example, updating the story
property or updating a
React component’s source will trigger useStory to rerender with the new
content.
info
In the future version hooks may be migrated to a new package to remove the React dependency from Storyteller.
Usage:
local React = require("@pkg/React")
local Storyteller = require("@pkg/Storyteller")
local useEffect = React.useEffect
local useRef = React.useRef
local e = React.createElement
local function StoryView(props: {
parent: Instance,
storyModule: ModuleScript,
storybook: Storybook,
})
local ref = useRef(nil :: Frame?)
local story = Storyteller.useStory(props.storyModule, props.storybook)
useEffect(function()
if ref.current then
local renderer = Storyteller.createRendererForStory(story)
Storyteller.render(renderer, ref.current, story)
end
end, { story })
return e("Frame", {
Size = UDim2.fromScale(1, 1),
BackgroundTransparency = 1,
ref = ref,
})
end
return StoryView
useStorybooks
ReactStorybookStoryteller.
useStorybooks
(
parent:
Instance
) →
{
available:
{
LoadedStorybook
}
,
unavailable:
{
UnavailableStorybook
}
,
}
Performs all the discovery and loading of Storybook modules that would normally be done via individual API members.
This hook makes it possible to conveniently load (and reload) Storybooks for use in React UI.
info
In the future version hooks may be migrated to a new package to remove the React dependency from Storyteller.
Usage:
local React = require("@pkg/React")
local Storyteller = require("@pkg/Storyteller")
local e = React.createElement
local function StorybookList(props: {
parent: Instance,
})
local storybooks = Storyteller.useStorybooks(props.parent)
local children = {}
for index, storybook in storybooks do
children[storybook.name] = e("TextLabel", {
Text = storybook.name,
LayoutOrder = index,
}),
end
return e("Frame", {
Size = UDim2.fromScale(1, 1),
BackgroundTransparency = 1,
}, {
Layout = e("UIListLayout", {
SortOrder = Enum.SortOrder.LayoutOrder
}),
}, children)
end
return StorybookList
This hook triggers a rerender when a Storybook module changes. For example,
updating the storyRoots
of a Storybook will trigger a rerender, and when
paired with useStory
you can get live updates to which Stories a Storybook
manages.
findStorybookModules
StorybookDiscoveryDiscovers all Storybook modules that are descendants of parent
.
This is the first step in the discovery of Stories. Once you load a
Storybook, you can then use its storyRoots
array to discover all the
Stories it manages.