Merge branch 'master' of github.com:storybooks/storybook into addon-resources

This commit is contained in:
Neville Mehta 2018-10-20 11:39:39 -07:00
commit 593387bd59
980 changed files with 19009 additions and 36347 deletions

View File

@ -28,6 +28,26 @@
"@babel/preset-env",
"babel-preset-vue"
]
},
{
"test": [
"./lib/core/src/server",
"./lib/node-logger",
"./lib/codemod",
"./addons/storyshots",
"./addons/storysource/src/loader",
"./app/**/src/server/**"
],
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "8.11"
}
}
]
]
}
]
}

View File

@ -1,19 +0,0 @@
{
"ignore": [
"addons/**/.storybook/**/*.js",
"lib/cli/generators/**/.stories/**.js",
"*.ts"
],
"critics": {
"wc": {
"limit": 500
}
},
"dependencies": {
"mute": [
"shelljs",
"eslint-plugin-json",
"remark-lint-code-eslint"
]
}
}

View File

@ -36,20 +36,11 @@ jobs:
root: .
paths:
- node_modules
- examples/angular-cli/node_modules
- examples/cra-kitchen-sink/node_modules
- examples/mithril-kitchen-sink/node_modules
- examples/official-storybook/node_modules
- examples/polymer-cli/node_modules
- examples/vue-kitchen-sink/node_modules
- examples/svelte-kitchen-sink/node_modules
- examples/marko-cli/node_modules
- examples/html-kitchen-sink/node_modules
- examples/riot-kitchen-sink/node_modules
- examples
- addons
- app
- lib
example-kitchen-sinks:
examples:
<<: *defaults
steps:
- checkout
@ -78,6 +69,11 @@ jobs:
command: |
cd examples/angular-cli
yarn build-storybook
- run:
name: Build ember-cli
command: |
cd examples/ember-cli
yarn build-storybook
- run:
name: Build polymer-cli
command: |
@ -140,6 +136,11 @@ jobs:
command: |
cd examples/angular-cli
yarn storybook --smoke-test
- run:
name: Run ember-cli (smoke test)
command: |
cd examples/ember-cli
yarn storybook --smoke-test
- run:
name: Run polymer-cli (smoke test)
command: |
@ -165,7 +166,7 @@ jobs:
command: |
cd examples/riot-kitchen-sink
yarn storybook --smoke-test
react-native:
native-smoke-tests:
<<: *defaults
steps:
- checkout
@ -173,22 +174,12 @@ jobs:
at: .
- run:
name: Bootstrap
command: yarn bootstrap --reactnative --reactnativeapp
- run:
name: Run React-Native example
command: |
cd examples/react-native-vanilla
yarn storybook --smoke-test
command: yarn bootstrap --reactnativeapp
- run:
name: Run React-Native-App example
command: |
cd examples/crna-kitchen-sink
cd examples-native/crna-kitchen-sink
yarn storybook --smoke-test
- run:
name: Run React-Native unit tests
command: |
yarn test --coverage --runInBand --reactnative
yarn coverage
docs:
<<: *defaults
steps:
@ -226,7 +217,7 @@ jobs:
- run:
name: Lint
command: yarn lint
unit-test:
test:
<<: *defaults
steps:
- checkout
@ -248,10 +239,8 @@ jobs:
- run:
name: Upload coverage
command: yarn coverage
cli:
cli-test:
<<: *defaults
docker:
- image: andthensome/docker-node-rsync
environment:
BASH_ENV: ~/.bashrc
steps:
@ -262,10 +251,8 @@ jobs:
name: Test
command: yarn test --cli
no_output_timeout: 1800
cli-latest-cra:
cli-test-latest-cra:
<<: *defaults
docker:
- image: andthensome/docker-node-rsync
environment:
BASH_ENV: ~/.bashrc
steps:
@ -285,24 +272,24 @@ workflows:
requires:
- docs
- build
- example-kitchen-sinks:
- examples:
requires:
- build
- smoke-tests:
requires:
- build
- react-native:
- native-smoke-tests:
requires:
- build
- unit-test:
- test:
requires:
- build
- coverage:
requires:
- unit-test
- cli:
- test
- cli-test:
requires:
- build
- cli-latest-cra:
- cli-test-latest-cra:
requires:
- build

View File

@ -57,6 +57,7 @@ module.exports = {
{
devDependencies: [
'examples/**',
'examples-native/**',
'**/example/**',
'*.js',
'**/*.test.js',

4
.github/CODEOWNERS vendored
View File

@ -28,13 +28,13 @@
/examples/angular-cli/ @igor-dv @alterx
/examples/cra-kitchen-sink/ @ndelangen @UsulPro @hypnosphi
/examples/crna-kitchen-sink/ @Gongreg @danielduan
/examples/official-storybook/ @hypnosphi @danielduan @UsulPro
/examples/polymer-cli/ @naipath @igor-dv
/examples/react-native-vanilla/ @tmeasday @danielduan
/examples/vue-kitchen-sink/ @igor-dv @alexandrebodin
/examples/svelte-kitchen-sink/ @plumpNation
/examples-native/crna-kitchen-sink/ @Gongreg @danielduan
/lib/addons/ @ndelangen @theinterned
/lib/channel-postmessage/ @mnmtanish @ndelangen
/lib/channel-websocket/ @mnmtanish @ndelangen

1
.remarkignore Normal file
View File

@ -0,0 +1 @@
CHANGELOG.md

View File

@ -18,15 +18,17 @@ object Project : Project({
vcsRoot(OpenSourceProjects_Storybook_HttpsGithubComStorybooksStorybookRefsHeadsMaster1)
vcsRoot(OpenSourceProjects_Storybook_HttpsGithubComStorybooksStorybookRefsHeadsMaster)
buildType(OpenSourceProjects_Storybook_Bootstrap)
buildType(OpenSourceProjects_Storybook_CliTestLatestCra)
buildType(OpenSourceProjects_Storybook_Examples)
buildType(OpenSourceProjects_Storybook_Danger)
buildType(OpenSourceProjects_Storybook_ReactNative)
buildType(OpenSourceProjects_Storybook_NativeSmokeTests)
buildType(OpenSourceProjects_Storybook_Docs)
buildType(OpenSourceProjects_Storybook_Build_2)
buildType(OpenSourceProjects_Storybook_CliTest)
buildType(OpenSourceProjects_Storybook_Test)
buildType(OpenSourceProjects_Storybook_Lint)
buildType(OpenSourceProjects_Storybook_Lint_Warnings)
buildType(OpenSourceProjects_Storybook_SmokeTests)
buildType(OpenSourceProjects_Storybook_Chromatic)

View File

@ -0,0 +1,78 @@
package OpenSourceProjects_Storybook.buildTypes
import jetbrains.buildServer.configs.kotlin.v2017_2.*
import jetbrains.buildServer.configs.kotlin.v2017_2.buildFeatures.commitStatusPublisher
import jetbrains.buildServer.configs.kotlin.v2017_2.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.vcs
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.retryBuild
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.VcsTrigger
object OpenSourceProjects_Storybook_Bootstrap : BuildType({
uuid = "9f9177e7-9ec9-4e2e-aabb-d304fd667712"
id = "OpenSourceProjects_Storybook_Bootstrap"
name = "Bootstrap"
artifactRules = """
addons/*/dist/** => dist.zip/addons
addons/storyshots/*/dist/** => dist.zip/addons/storyshots
app/*/dist/** => dist.zip/app
lib/*/dist/** => dist.zip/lib
""".trimIndent()
vcs {
root(OpenSourceProjects_Storybook.vcsRoots.OpenSourceProjects_Storybook_HttpsGithubComStorybooksStorybookRefsHeadsMaster)
}
steps {
script {
name = "Bootstrap"
scriptContent = """
#!/bin/sh
set -e -x
yarn
yarn bootstrap --core
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
}
triggers {
vcs {
quietPeriodMode = VcsTrigger.QuietPeriodMode.USE_DEFAULT
triggerRules = "-:comment=^TeamCity change:**"
branchFilter = """
+:pull/*
+:release/*
+:master
+:snyk-fix-*
""".trimIndent()
enabled = false
}
retryBuild {
delaySeconds = 60
enabled = false
}
}
features {
commitStatusPublisher {
publisher = github {
githubUrl = "https://api.github.com"
authType = personalToken {
token = "credentialsJSON:5ffe2d7e-531e-4f6f-b1fc-a41bfea26eaa"
}
}
param("github_oauth_user", "Hypnosphi")
}
}
requirements {
doesNotContain("env.OS", "Windows")
}
cleanup {
artifacts(days = 1)
}
})

View File

@ -4,8 +4,9 @@ import jetbrains.buildServer.configs.kotlin.v2017_2.*
import jetbrains.buildServer.configs.kotlin.v2017_2.buildFeatures.commitStatusPublisher
import jetbrains.buildServer.configs.kotlin.v2017_2.failureConditions.BuildFailureOnMetric
import jetbrains.buildServer.configs.kotlin.v2017_2.failureConditions.failOnMetricChange
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.VcsTrigger
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.vcs
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.VcsTrigger
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.finishBuildTrigger
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.retryBuild
import jetbrains.buildServer.configs.kotlin.v2017_2.buildFeatures.merge
import jetbrains.buildServer.configs.kotlin.v2017_2.ui.*
@ -32,12 +33,17 @@ object OpenSourceProjects_Storybook_Build_2 : BuildType({
+:pull/*
+:release/*
+:master
+:dependencies.io-*
+:snyk-fix-*
""".trimIndent()
}
retryBuild {
delaySeconds = 60
}
finishBuildTrigger {
enabled = false
buildTypeExtId = "OpenSourceProjects_Storybook_Bootstrap"
successfulOnly = true
branchFilter = ""
}
}
@ -64,7 +70,9 @@ object OpenSourceProjects_Storybook_Build_2 : BuildType({
param("github_oauth_user", "Hypnosphi")
}
merge {
branchFilter = "+:dependencies.io-*"
branchFilter = """
+:snyk-fix-*
""".trimIndent()
destinationBranch = "<default>"
commitMessage = "Merge branch '%teamcity.build.branch%'"
}
@ -86,7 +94,7 @@ object OpenSourceProjects_Storybook_Build_2 : BuildType({
onDependencyCancel = FailureAction.ADD_PROBLEM
}
}
dependency(OpenSourceProjects_Storybook.buildTypes.OpenSourceProjects_Storybook_ReactNative) {
dependency(OpenSourceProjects_Storybook.buildTypes.OpenSourceProjects_Storybook_NativeSmokeTests) {
snapshot {
onDependencyCancel = FailureAction.ADD_PROBLEM
}
@ -106,5 +114,10 @@ object OpenSourceProjects_Storybook_Build_2 : BuildType({
onDependencyCancel = FailureAction.ADD_PROBLEM
}
}
dependency(OpenSourceProjects_Storybook.buildTypes.OpenSourceProjects_Storybook_CliTest) {
snapshot {
onDependencyCancel = FailureAction.ADD_PROBLEM
}
}
}
})

View File

@ -21,17 +21,16 @@ object OpenSourceProjects_Storybook_Chromatic : BuildType({
}
steps {
script {
name = "Bootstrap"
scriptContent = """
yarn
yarn bootstrap --core
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
script {
name = "Chromatic"
scriptContent = "yarn chromatic"
scriptContent = """
#!/bin/sh
set -e -x
yarn
yarn chromatic
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
}
@ -49,6 +48,15 @@ object OpenSourceProjects_Storybook_Chromatic : BuildType({
}
dependencies {
dependency(OpenSourceProjects_Storybook.buildTypes.OpenSourceProjects_Storybook_Bootstrap) {
snapshot {
onDependencyFailure = FailureAction.FAIL_TO_START
}
artifacts {
artifactRules = "dist.zip!**"
}
}
allApps {
dependency(config) {
snapshot {}

View File

@ -3,9 +3,6 @@ package OpenSourceProjects_Storybook.buildTypes
import jetbrains.buildServer.configs.kotlin.v2017_2.*
import jetbrains.buildServer.configs.kotlin.v2017_2.buildFeatures.commitStatusPublisher
import jetbrains.buildServer.configs.kotlin.v2017_2.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.vcs
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.retryBuild
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.VcsTrigger
object OpenSourceProjects_Storybook_CliTest : BuildType({
uuid = "b1db1a3a-a4cf-46ea-8f55-98b86611f92e"
@ -18,33 +15,18 @@ object OpenSourceProjects_Storybook_CliTest : BuildType({
}
steps {
script {
name = "Bootstrap"
scriptContent = """
yarn
yarn bootstrap --core
""".trimIndent()
dockerImage = "andthensome/docker-node-rsync"
}
script {
name = "Test"
scriptContent = "yarn test --cli"
dockerImage = "andthensome/docker-node-rsync"
}
}
scriptContent = """
#!/bin/sh
triggers {
vcs {
quietPeriodMode = VcsTrigger.QuietPeriodMode.USE_DEFAULT
triggerRules = "-:comment=^TeamCity change:**"
branchFilter = """
+:pull/*
+:release/*
+:master
+:dependencies.io-*
set -e -x
yarn
yarn test --cli
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
retryBuild {}
}
features {
@ -59,6 +41,18 @@ object OpenSourceProjects_Storybook_CliTest : BuildType({
}
}
dependencies {
dependency(OpenSourceProjects_Storybook.buildTypes.OpenSourceProjects_Storybook_Bootstrap) {
snapshot {
onDependencyFailure = FailureAction.FAIL_TO_START
}
artifacts {
artifactRules = "dist.zip!**"
}
}
}
requirements {
doesNotContain("env.OS", "Windows")
}

View File

@ -4,6 +4,7 @@ import jetbrains.buildServer.configs.kotlin.v2017_2.*
import jetbrains.buildServer.configs.kotlin.v2017_2.buildFeatures.commitStatusPublisher
import jetbrains.buildServer.configs.kotlin.v2017_2.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.vcs
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.retryBuild
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.VcsTrigger
object OpenSourceProjects_Storybook_CliTestLatestCra : BuildType({
@ -17,18 +18,17 @@ object OpenSourceProjects_Storybook_CliTestLatestCra : BuildType({
}
steps {
script {
name = "Bootstrap"
scriptContent = """
yarn
yarn bootstrap --core
""".trimIndent()
dockerImage = "andthensome/docker-node-rsync"
}
script {
name = "Test"
scriptContent = "yarn test-latest-cra"
dockerImage = "andthensome/docker-node-rsync"
scriptContent = """
#!/bin/sh
set -e -x
yarn
yarn test-latest-cra
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
}
@ -36,7 +36,13 @@ object OpenSourceProjects_Storybook_CliTestLatestCra : BuildType({
vcs {
quietPeriodMode = VcsTrigger.QuietPeriodMode.USE_DEFAULT
triggerRules = "-:comment=^TeamCity change:**"
branchFilter = """
+:pull/*
+:release/*
+:master
""".trimIndent()
}
retryBuild {}
}
features {
@ -51,6 +57,18 @@ object OpenSourceProjects_Storybook_CliTestLatestCra : BuildType({
}
}
dependencies {
dependency(OpenSourceProjects_Storybook.buildTypes.OpenSourceProjects_Storybook_Bootstrap) {
snapshot {
onDependencyFailure = FailureAction.FAIL_TO_START
}
artifacts {
artifactRules = "dist.zip!**"
}
}
}
requirements {
doesNotContain("env.OS", "Windows")
}

View File

@ -13,8 +13,8 @@ object OpenSourceProjects_Storybook_Danger : BuildType({
name = "Danger"
params {
password("env.DANGER_GITHUB_API_TOKEN", "credentialsJSON:8fa112e0-d0e0-4f9f-9f18-01471a999b4d", display = ParameterDisplay.HIDDEN)
param("env.PULL_REQUEST_URL", "https://github.com/storybooks/storybook/%teamcity.build.branch%")
password("env.DANGER_GITHUB_API_TOKEN", "credentialsJSON:7f0943ab-dfca-49dd-b926-03062007bfd0")
param("env.PULL_REQUEST_URL", "https://github.com/storybooks/storybook/pull/%teamcity.build.branch%")
}
vcs {
@ -24,14 +24,16 @@ object OpenSourceProjects_Storybook_Danger : BuildType({
}
steps {
script {
name = "Install"
scriptContent = "yarn"
dockerImage = "node:%docker.node.version%"
}
script {
name = "Danger"
scriptContent = "yarn danger ci"
scriptContent = """
#!/bin/sh
set -e -x
yarn
yarn danger ci
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
}
@ -39,7 +41,6 @@ object OpenSourceProjects_Storybook_Danger : BuildType({
triggers {
vcs {
quietPeriodMode = VcsTrigger.QuietPeriodMode.USE_DEFAULT
triggerRules = "-:comment=^TeamCity change:**"
branchFilter = """
+:*
-:master
@ -60,6 +61,12 @@ object OpenSourceProjects_Storybook_Danger : BuildType({
}
param("github_oauth_user", "Hypnosphi")
}
feature {
type = "pullRequests"
param("filterAuthorRole", "EVERYBODY")
param("authenticationType", "token")
param("secure:accessToken", "credentialsJSON:5ffe2d7e-531e-4f6f-b1fc-a41bfea26eaa")
}
}
requirements {

View File

@ -3,7 +3,6 @@ package OpenSourceProjects_Storybook.buildTypes
import jetbrains.buildServer.configs.kotlin.v2017_2.*
import jetbrains.buildServer.configs.kotlin.v2017_2.buildFeatures.commitStatusPublisher
import jetbrains.buildServer.configs.kotlin.v2017_2.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.vcs
object OpenSourceProjects_Storybook_Docs : BuildType({
uuid = "1bda59b5-d08d-4fd8-b317-953e7d79d881"
@ -22,23 +21,18 @@ object OpenSourceProjects_Storybook_Docs : BuildType({
}
steps {
script {
name = "Install"
workingDir = "docs"
scriptContent = "yarn install --frozen-lockfile"
dockerImage = "node:%docker.node.version%"
}
script {
name = "Build"
workingDir = "docs"
scriptContent = "yarn build"
dockerImage = "node:%docker.node.version%"
}
}
scriptContent = """
#!/bin/sh
triggers {
vcs {
enabled = false
set -e -x
yarn --frozen-lockfile
yarn build
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
}

View File

@ -23,21 +23,14 @@ examples/official-storybook/image-snapshots/__image_snapshots__ => image-snapsho
}
steps {
script {
name = "Bootstrap"
scriptContent = """
yarn
yarn bootstrap --core
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
script {
name = "official-storybook"
scriptContent = """
#!/bin/sh
set -e -x
yarn
cd examples/official-storybook
rm -rf storybook-static
yarn build-storybook
@ -90,6 +83,15 @@ examples/official-storybook/image-snapshots/__image_snapshots__ => image-snapsho
}
dependencies {
dependency(OpenSourceProjects_Storybook.buildTypes.OpenSourceProjects_Storybook_Bootstrap) {
snapshot {
onDependencyFailure = FailureAction.FAIL_TO_START
}
artifacts {
artifactRules = "dist.zip!**"
}
}
allApps {
dependency(config) {
snapshot {}

View File

@ -3,7 +3,8 @@ package OpenSourceProjects_Storybook.buildTypes
import jetbrains.buildServer.configs.kotlin.v2017_2.*
import jetbrains.buildServer.configs.kotlin.v2017_2.buildFeatures.commitStatusPublisher
import jetbrains.buildServer.configs.kotlin.v2017_2.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.vcs
import jetbrains.buildServer.configs.kotlin.v2017_2.failureConditions.BuildFailureOnMetric
import jetbrains.buildServer.configs.kotlin.v2017_2.failureConditions.failOnMetricChange
object OpenSourceProjects_Storybook_Lint : BuildType({
uuid = "42cfbb9a-f35b-4f96-afae-0b508927a737"
@ -17,24 +18,18 @@ object OpenSourceProjects_Storybook_Lint : BuildType({
steps {
script {
name = "Bootstrap"
name = "Lint"
scriptContent = """
#!/bin/sh
set -e -x
yarn
yarn bootstrap --core --docs
yarn bootstrap --docs
yarn lint:ci
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
script {
name = "Lint"
scriptContent = "yarn lint:ci"
dockerImage = "node:%docker.node.version%"
}
}
triggers {
vcs {
enabled = false
}
}
features {
@ -49,6 +44,18 @@ object OpenSourceProjects_Storybook_Lint : BuildType({
}
}
dependencies {
dependency(OpenSourceProjects_Storybook.buildTypes.OpenSourceProjects_Storybook_Bootstrap) {
snapshot {
onDependencyFailure = FailureAction.FAIL_TO_START
}
artifacts {
artifactRules = "dist.zip!**"
}
}
}
requirements {
doesNotContain("env.OS", "Windows")
}
@ -56,4 +63,15 @@ object OpenSourceProjects_Storybook_Lint : BuildType({
cleanup {
artifacts(days = 1)
}
failureConditions {
failOnMetricChange {
metric = BuildFailureOnMetric.MetricType.INSPECTION_ERROR_COUNT
threshold = 0
units = BuildFailureOnMetric.MetricUnit.DEFAULT_UNIT
comparison = BuildFailureOnMetric.MetricComparison.MORE
compareTo = value()
param("anchorBuild", "lastSuccessful")
}
}
})

View File

@ -0,0 +1,91 @@
package OpenSourceProjects_Storybook.buildTypes
import jetbrains.buildServer.configs.kotlin.v2017_2.*
import jetbrains.buildServer.configs.kotlin.v2017_2.buildFeatures.commitStatusPublisher
import jetbrains.buildServer.configs.kotlin.v2017_2.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.vcs
import jetbrains.buildServer.configs.kotlin.v2017_2.failureConditions.BuildFailureOnMetric
import jetbrains.buildServer.configs.kotlin.v2017_2.failureConditions.failOnMetricChange
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.VcsTrigger
object OpenSourceProjects_Storybook_Lint_Warnings : BuildType({
uuid = "42cfbb9a-f35b-4f96-afae-0b508927a738"
id = "OpenSourceProjects_Storybook_Lint_Warnings"
name = "Lint Warnings"
vcs {
root(OpenSourceProjects_Storybook.vcsRoots.OpenSourceProjects_Storybook_HttpsGithubComStorybooksStorybookRefsHeadsMaster)
}
steps {
script {
name = "Lint"
scriptContent = """
#!/bin/sh
set -e -x
yarn
yarn bootstrap --docs
yarn lint:ci
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
}
triggers {
vcs {
quietPeriodMode = VcsTrigger.QuietPeriodMode.USE_DEFAULT
triggerRules = "-:comment=^TeamCity change:**"
branchFilter = """
+:pull/*
+:release/*
+:master
""".trimIndent()
}
}
features {
commitStatusPublisher {
publisher = github {
githubUrl = "https://api.github.com"
authType = personalToken {
token = "credentialsJSON:5ffe2d7e-531e-4f6f-b1fc-a41bfea26eaa"
}
}
param("github_oauth_user", "Hypnosphi")
}
}
dependencies {
dependency(OpenSourceProjects_Storybook.buildTypes.OpenSourceProjects_Storybook_Bootstrap) {
snapshot {
onDependencyFailure = FailureAction.FAIL_TO_START
}
artifacts {
artifactRules = "dist.zip!**"
}
}
}
requirements {
doesNotContain("env.OS", "Windows")
}
cleanup {
artifacts(days = 1)
}
failureConditions {
failOnMetricChange {
metric = BuildFailureOnMetric.MetricType.INSPECTION_WARN_COUNT
threshold = 0
units = BuildFailureOnMetric.MetricUnit.DEFAULT_UNIT
comparison = BuildFailureOnMetric.MetricComparison.MORE
compareTo = value()
param("anchorBuild", "lastSuccessful")
}
}
})

View File

@ -4,12 +4,10 @@ import jetbrains.buildServer.configs.kotlin.v2017_2.*
import jetbrains.buildServer.configs.kotlin.v2017_2.buildFeatures.commitStatusPublisher
import jetbrains.buildServer.configs.kotlin.v2017_2.buildSteps.script
object OpenSourceProjects_Storybook_ReactNative : BuildType({
object OpenSourceProjects_Storybook_NativeSmokeTests : BuildType({
uuid = "ac276912-df1a-44f1-8de2-056276193ce8"
id = "OpenSourceProjects_Storybook_ReactNative"
name = "React Native"
artifactRules = "examples/react-native-vanilla/coverage/lcov-report => coverage.zip"
id = "OpenSourceProjects_Storybook_NativeSmokeTests"
name = "Native Smoke Tests"
params {
param("env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD", "true")
@ -22,38 +20,20 @@ object OpenSourceProjects_Storybook_ReactNative : BuildType({
}
steps {
script {
name = "Bootstrap"
scriptContent = """
yarn
yarn bootstrap --core --reactnative --reactnativeapp
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
script {
name = "react-native-vanilla"
scriptContent = """
cd examples/react-native-vanilla
yarn storybook --smoke-test
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
script {
name = "crna-kitchen-sink"
scriptContent = """
cd examples/crna-kitchen-sink
#!/bin/sh
set -e -x
yarn
yarn bootstrap --reactnativeapp
cd examples-native/crna-kitchen-sink
yarn storybook --smoke-test
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
script {
name = "Test"
scriptContent = """
yarn test --reactnative --coverage --runInBand --teamcity
yarn coverage
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
}
features {
@ -68,6 +48,18 @@ object OpenSourceProjects_Storybook_ReactNative : BuildType({
}
}
dependencies {
dependency(OpenSourceProjects_Storybook.buildTypes.OpenSourceProjects_Storybook_Bootstrap) {
snapshot {
onDependencyFailure = FailureAction.FAIL_TO_START
}
artifacts {
artifactRules = "dist.zip!**"
}
}
}
requirements {
doesNotContain("env.OS", "Windows")
}

View File

@ -1,62 +0,0 @@
package OpenSourceProjects_Storybook.buildTypes
import jetbrains.buildServer.configs.kotlin.v2017_2.*
import jetbrains.buildServer.configs.kotlin.v2017_2.buildFeatures.commitStatusPublisher
import jetbrains.buildServer.configs.kotlin.v2017_2.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2017_2.failureConditions.BuildFailureOnMetric
import jetbrains.buildServer.configs.kotlin.v2017_2.failureConditions.failOnMetricChange
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.VcsTrigger
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.vcs
object OpenSourceProjects_Storybook_SBNext : BuildType({
uuid = "dc66f07a-281f-4434-97ca-f1480b7cfc51"
id = "OpenSourceProjects_Storybook_SBNext"
name = "SBNext"
artifactRules = "ui/out => demo.zip"
vcs {
root("OpenSourceProjects_Storybook_SBNext")
}
steps {
script {
name = "Install"
scriptContent = "yarn"
dockerImage = "node:%docker.node.version%"
}
script {
name = "Lint"
scriptContent = "yarn lint"
dockerImage = "node:%docker.node.version%"
}
script {
name = "Test"
enabled = false
scriptContent = "yarn test"
dockerImage = "node:%docker.node.version%"
}
script {
name = "Build"
workingDir = "server"
scriptContent = "yarn build"
dockerImage = "node:%docker.node.version%"
}
script {
name = "Export"
workingDir = "demo"
scriptContent = "yarn export"
dockerImage = "node:%docker.node.version%"
}
}
triggers {
vcs {
}
}
requirements {
doesNotContain("env.OS", "Windows")
}
})

View File

@ -16,11 +16,8 @@ object OpenSourceProjects_Storybook_SmokeTests : BuildType({
steps {
script {
name = "Bootstrap"
scriptContent = """
yarn
yarn bootstrap --core
""".trimIndent()
name = "Install"
scriptContent = "yarn"
dockerImage = "node:%docker.node.version%"
}
allApps {
@ -65,6 +62,18 @@ object OpenSourceProjects_Storybook_SmokeTests : BuildType({
}
}
dependencies {
dependency(OpenSourceProjects_Storybook.buildTypes.OpenSourceProjects_Storybook_Bootstrap) {
snapshot {
onDependencyFailure = FailureAction.FAIL_TO_START
}
artifacts {
artifactRules = "dist.zip!**"
}
}
}
requirements {
doesNotContain("env.OS", "Windows")
}

View File

@ -3,7 +3,6 @@ package OpenSourceProjects_Storybook.buildTypes
import jetbrains.buildServer.configs.kotlin.v2017_2.*
import jetbrains.buildServer.configs.kotlin.v2017_2.buildFeatures.commitStatusPublisher
import jetbrains.buildServer.configs.kotlin.v2017_2.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2017_2.triggers.vcs
object OpenSourceProjects_Storybook_Test : BuildType({
uuid = "9f9177e7-9ec9-4e2e-aabb-d304fd667711"
@ -18,30 +17,20 @@ object OpenSourceProjects_Storybook_Test : BuildType({
}
steps {
script {
name = "Bootstrap"
scriptContent = """
yarn
yarn bootstrap --core
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
script {
name = "Test"
scriptContent = """
#!/bin/sh
set -e -x
yarn
yarn test --core --coverage --runInBand --teamcity
yarn coverage
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
}
triggers {
vcs {
enabled = false
}
}
features {
commitStatusPublisher {
publisher = github {
@ -54,6 +43,18 @@ object OpenSourceProjects_Storybook_Test : BuildType({
}
}
dependencies {
dependency(OpenSourceProjects_Storybook.buildTypes.OpenSourceProjects_Storybook_Bootstrap) {
snapshot {
onDependencyFailure = FailureAction.FAIL_TO_START
}
artifacts {
artifactRules = "dist.zip!**"
}
}
}
requirements {
doesNotContain("env.OS", "Windows")
}

View File

@ -14,9 +14,9 @@ enum class StorybookApp(val appName: String, val exampleDir: String, val merged:
MITHRIL("Mithril", "mithril-kitchen-sink"),
HTML("HTML", "html-kitchen-sink"),
MARKO("Marko", "marko-cli"),
HYPERAPP("Hyperapp", "hyperapp-kitchen-sink", false),
SVELTE("Svelte", "svelte-kitchen-sink"),
RIOT("Riot", "riot-kitchen-sink");
RIOT("Riot", "riot-kitchen-sink"),
EMBER("Ember", "ember-cli");
val lowerName = appName.toLowerCase()
@ -36,14 +36,6 @@ enum class StorybookApp(val appName: String, val exampleDir: String, val merged:
artifactRules = artifactPath
steps {
script {
name = "Bootstrap"
scriptContent = """
yarn
yarn bootstrap --core
""".trimIndent()
dockerImage = "node:%docker.node.version%"
}
script {
name = "build"
scriptContent = """
@ -51,6 +43,7 @@ enum class StorybookApp(val appName: String, val exampleDir: String, val merged:
set -e -x
yarn
cd examples/$exampleDir
yarn build-storybook
""".trimIndent()
@ -82,6 +75,18 @@ enum class StorybookApp(val appName: String, val exampleDir: String, val merged:
}
}
dependencies {
dependency(OpenSourceProjects_Storybook.buildTypes.OpenSourceProjects_Storybook_Bootstrap) {
snapshot {
onDependencyFailure = FailureAction.FAIL_TO_START
}
artifacts {
artifactRules = "dist.zip!**"
}
}
}
requirements {
doesNotContain("env.OS", "Windows")
}

View File

@ -0,0 +1,20 @@
package OpenSourceProjects_Storybook.patches.buildTypes
import jetbrains.buildServer.configs.kotlin.v2017_2.*
import jetbrains.buildServer.configs.kotlin.v2017_2.ui.*
/*
This patch script was generated by TeamCity on settings change in UI.
To apply the patch, change the buildType with uuid = '759f0116-2f7d-4c03-8220-56e4ab03be3a' (id = 'OpenSourceProjects_Storybook_Danger')
accordingly, and delete the patch script.
*/
changeBuildType("759f0116-2f7d-4c03-8220-56e4ab03be3a") {
params {
expect {
password("env.DANGER_GITHUB_API_TOKEN", "credentialsJSON:7f0943ab-dfca-49dd-b926-03062007bfd0")
}
update {
password("env.DANGER_GITHUB_API_TOKEN", "credentialsJSON:9ac87388-d267-4def-a10e-3e596369f644")
}
}
}

View File

@ -8,7 +8,6 @@ object OpenSourceProjects_Storybook_HttpsGithubComStorybooksStorybookRefsHeadsMa
id = "OpenSourceProjects_Storybook_HttpsGithubComStorybooksStorybookRefsHeadsMaster1"
name = "https://github.com/storybooks/storybook#refs/heads/master (1)"
url = "git@github.com:storybooks/storybook.git"
branchSpec = "+:refs/(pull/*)/head"
authMethod = uploadedKey {
userName = "git"
uploadedKey = "Storybook bot"

View File

@ -1,19 +1,22 @@
## Addon / Framework Support Table
| | [React](app/react)|[React Native](app/react-native)|[Vue](app/vue)|[Angular](app/angular)| [Polymer](app/polymer)| [Mithril](app/mithril)| [HTML](app/html)| [Marko](app/marko)| [Svelte](app/svelte)| [Riot](app/riot)|
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|[a11y](addons/a11y) |+| |+|+|+|+|+|+| | |
|[actions](addons/actions) |+|+|+|+|+|+|+|+|+|+|
|[backgrounds](addons/backgrounds) |+| |+|+|+|+|+|+|+|+|
|[centered](addons/centered) |+| |+|+| |+|+| |+| |
|[events](addons/events) |+| |+|+|+|+|+|+| | |
|[graphql](addons/graphql) |+| | | | | | | | | |
|[info](addons/info) |+| | | | | | | | | |
|[jest](addons/jest) |+| | |+| | |+| | | |
|[knobs](addons/knobs) |+|+|+|+|+|+|+|+|+|+|
|[links](addons/links) |+|+|+|+|+|+|+| |+|+|
|[notes](addons/notes) |+| |+|+|+|+|+| |+|+|
|[options](addons/options) |+|+|+|+|+|+|+| |+|+|
|[storyshots](addons/storyshots) |+|+|+|+| | |+| |+|+|
|[storysource](addons/storysource)|+| |+|+|+|+|+|+|+|+|
|[viewport](addons/viewport) |+| |+|+|+|+|+|+|+|+|
## Addon / Framework Support Table
| | [React](app/react)|[React Native](app/react-native)|[Vue](app/vue)|[Angular](app/angular)| [Polymer](app/polymer)| [Mithril](app/mithril)| [HTML](app/html)| [Marko](app/marko)| [Svelte](app/svelte)| [Riot](app/riot)| [Ember](app/ember)|
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|[a11y](addons/a11y) |+| |+|+|+|+|+|+| | |+|
|[actions](addons/actions) |+|+|+|+|+|+|+|+|+|+|+|
|[backgrounds](addons/backgrounds) |+|*|+|+|+|+|+|+|+|+|+|
|[centered](addons/centered) |+| |+|+| |+|+| |+| |+|
|[events](addons/events) |+| |+|+|+|+|+|+| | |+|
|[graphql](addons/graphql) |+| | | | | | | | | | |
|[google-analytics](addons/google-analytics) |+|+|+|+|+|+|+|+|+|+|+|
|[info](addons/info) |+| | | | | | | | | | |
|[jest](addons/jest) |+| | |+| | |+| | | | |
|[knobs](addons/knobs) |+|+*|+|+|+|+|+|+|+|+|+|
|[links](addons/links) |+|+|+|+|+|+|+| |+|+|+|
|[notes](addons/notes) |+|+*|+|+|+|+|+| |+|+|+|
|[options](addons/options) |+|+|+|+|+|+|+| |+|+|+|
|[storyshots](addons/storyshots) |+|+|+|+| | |+| |+|+| |
|[storysource](addons/storysource) |+| |+|+|+|+|+|+|+|+|+|
|[viewport](addons/viewport) |+| |+|+|+|+|+|+|+|+|+|
`*` - React Native on device addon (addons/onDevice-\<name>)

View File

@ -1,3 +1,192 @@
# 4.0.0-rc.1
2018-October-18
#### Bug Fixes
- Angular: expose webpackFinal extension [#4431](https://github.com/storybooks/storybook/pull/4431)
- Addon-Knobs: fix ints as values [#4465](https://github.com/storybooks/storybook/pull/4465)
#### Maintenance
- Add Angular 6 fixture to the sb-cli tests [#4464](https://github.com/storybooks/storybook/pull/4464)
#### Dependency Upgrades
- Require React 16.3 as a peer dependency [#4458](https://github.com/storybooks/storybook/pull/4458)
- Bump @ember/test-helpers from 0.7.26 to 0.7.27 [#4455](https://github.com/storybooks/storybook/pull/4455)
- Bump eslint-plugin-jest from 21.25.0 to 21.25.1 [#4456](https://github.com/storybooks/storybook/pull/4456)
- Bump autoprefixer from 9.2.0 to 9.2.1 [#4457](https://github.com/storybooks/storybook/pull/4457)
- Bump @types/node from 10.11.7 to 10.12.0 [#4434](https://github.com/storybooks/storybook/pull/4434)
- Bump ember-cli-inject-live-reload from 2.0.0 to 2.0.1 [#4435](https://github.com/storybooks/storybook/pull/4435)
- Bump gatsby-plugin-sharp from 1.6.48 to 2.0.7 in /docs [#4438](https://github.com/storybooks/storybook/pull/4438)
- Bump marked from 0.4.0 to 0.5.1 in /docs [#4437](https://github.com/storybooks/storybook/pull/4437)
- Bump highlight.js from 9.12.0 to 9.13.0 in /docs [#4440](https://github.com/storybooks/storybook/pull/4440)
# 4.0.0-rc.0
2018-October-15
#### Features
- Addon: google analytics [#4138](https://github.com/storybooks/storybook/pull/4138)
#### Bug Fixes
- Improve environment var loading [#4413](https://github.com/storybooks/storybook/pull/4413)
#### Maintenance
- Skip preflight check when starting cra kitchen sink [#4408](https://github.com/storybooks/storybook/pull/4408)
- Change crna-kitchen-sink path and Some CI maintenance [#4409](https://github.com/storybooks/storybook/pull/4409)
- Create ember entry point to official storybook [#4426](https://github.com/storybooks/storybook/pull/4426)
#### Dependency Upgrades
- Bump ember-cli from 3.4.3 to 3.5.0 [#4429](https://github.com/storybooks/storybook/pull/4429)
- Bump react-native-modal-selector from 0.0.27 to 0.0.29 [#4428](https://github.com/storybooks/storybook/pull/4428)
- Bump ember-cli-inject-live-reload from 1.8.2 to 1.10.1 [#4423](https://github.com/storybooks/storybook/pull/4423)
- Bump html-webpack-plugin from 4.0.0-beta.1 to 4.0.0-beta.2 [#4421](https://github.com/storybooks/storybook/pull/4421)
- Bump react-scripts from 2.0.4 to 2.0.5 [#4420](https://github.com/storybooks/storybook/pull/4420)
- Bump autoprefixer from 9.1.5 to 9.2.0 [#4417](https://github.com/storybooks/storybook/pull/4417)
- Bump redux from 4.0.0 to 4.0.1 [#4419](https://github.com/storybooks/storybook/pull/4419)
- Bump ts-loader from 5.2.1 to 5.2.2 [#4418](https://github.com/storybooks/storybook/pull/4418)
- Bump eslint-plugin-jest from 21.24.1 to 21.25.0 [#4424](https://github.com/storybooks/storybook/pull/4424)
- Bump lazy-universal-dotenv from 1.9.1 to 2.0.0 [#4422](https://github.com/storybooks/storybook/pull/4422)
# 4.0.0-alpha.25
2018-October-13
#### Breaking Changes
- CLI: Rename CLI to sb [#4345](https://github.com/storybooks/storybook/pull/4345)
- React Native: Remove the packager from storybook [#4261](https://github.com/storybooks/storybook/pull/4261)
- React-Native: On-device addons [#4381](https://github.com/storybooks/storybook/pull/4381)
#### Features
- Storybook version update check [#4334](https://github.com/storybooks/storybook/pull/4334)
- CLI: specify project type interactively or as option [#4184](https://github.com/storybooks/storybook/pull/4184)
- Addon-Jest: expand supported file types [#3983](https://github.com/storybooks/storybook/pull/3983)
- CLI-less Node api [#4344](https://github.com/storybooks/storybook/pull/4344)
- React-Native: Updated channel to support async option [#4326](https://github.com/storybooks/storybook/pull/4326)
- React-Native: On-device addons for notes, knobs, backgrounds [#4327](https://github.com/storybooks/storybook/pull/4327)
- Angular: Add support for "baseUrl" and "paths" from angular-cli [#4162](https://github.com/storybooks/storybook/pull/4162)
- Angular: Added basePath support [#4323](https://github.com/storybooks/storybook/pull/4323)
- Vue: support string-only component [#4285](https://github.com/storybooks/storybook/pull/4285)
- Storyshots: Add snapshot serializer option [#4283](https://github.com/storybooks/storybook/pull/4283)
- Storyshots: Support story-specific options as function [#4282](https://github.com/storybooks/storybook/pull/4282)
#### Bug Fixes
- React-native: Remove deprecated attempt to load default addons [#4308](https://github.com/storybooks/storybook/pull/4308)
- Fix panel layouts [#4304](https://github.com/storybooks/storybook/pull/4304)
- [logging] better error logging for when opn fails to opn [#4348](https://github.com/storybooks/storybook/pull/4348)
- Fix iPhone viewport dimensions [#4293](https://github.com/storybooks/storybook/pull/4293)
- Fix Array.js value to string [#4336](https://github.com/storybooks/storybook/pull/4336)
- Fixes to cli ember support [#4318](https://github.com/storybooks/storybook/pull/4318)
- Update `addon-jest` to new propType [#4252](https://github.com/storybooks/storybook/pull/4252)
#### Maintenance
- Remove CRNA fixture [#4346](https://github.com/storybooks/storybook/pull/4346)
- Try to fix cli tests [#4338](https://github.com/storybooks/storybook/pull/4338)
- Updated installation for Angular [#4302](https://github.com/storybooks/storybook/pull/4302)
- Fix the broken lint [#4310](https://github.com/storybooks/storybook/pull/4310)
- [ember] add dependencies to root application [#4309](https://github.com/storybooks/storybook/pull/4309)
#### Dependency Upgrades
- Knobs/replace datepicker [#4380](https://github.com/storybooks/storybook/pull/4380)
- Re-generate lockfiles [#4404](https://github.com/storybooks/storybook/pull/4404)
- Run `yarn upgrade-interactive --latest` in root and docs [#4403](https://github.com/storybooks/storybook/pull/4403)
- chore(deps): #4267 upgrade lodash to latest [#4284](https://github.com/storybooks/storybook/pull/4284)
- Bump express from 4.16.3 to 4.16.4 [#4370](https://github.com/storybooks/storybook/pull/4370)
- Bump @angular/cli from 6.2.4 to 6.2.5 [#4390](https://github.com/storybooks/storybook/pull/4390)
- CHANGE back to use html-webpack-plugin to keep compatibility with plugins that depend on it [#4375](https://github.com/storybooks/storybook/pull/4375)
- Bump danger from 4.4.6 to 4.4.7 [#4365](https://github.com/storybooks/storybook/pull/4365)
- Bump @storybook/react from 3.4.8 to 3.4.11 in /docs [#4354](https://github.com/storybooks/storybook/pull/4354)
- Bump sitemap from 1.13.0 to 2.0.1 in /docs [#4356](https://github.com/storybooks/storybook/pull/4356)
- Bump husky from 1.1.1 to 1.1.2 [#4358](https://github.com/storybooks/storybook/pull/4358)
- Tech/upgrades 5 [#4347](https://github.com/storybooks/storybook/pull/4347)
# 4.0.0-alpha.24
2018-October-04
#### Features
- Ember: add ember support [#4237](https://github.com/storybooks/storybook/pull/4237)
- Riot: support the tagConstructor option [#4258](https://github.com/storybooks/storybook/pull/4258)
- Presets: Add "addons" and "config" to preset extensions [#4240](https://github.com/storybooks/storybook/pull/4240)
#### Bug Fixes
- Webpack: Fix broken SVGs [#4260](https://github.com/storybooks/storybook/pull/4260)
- Babel/minify: use `builtIns: false` [#4262](https://github.com/storybooks/storybook/pull/4262)
- Addon-Notes: Fix how markdownOptions are passed to marked [#4242](https://github.com/storybooks/storybook/pull/4242)
- Addon-Knobs: Fix broken colorpicker [#4222](https://github.com/storybooks/storybook/pull/4222)
# 4.0.0-alpha.23
2018-September-25
#### Features
- Angular build time optimization [#4118](https://github.com/storybooks/storybook/pull/4118)
- Pass Jest done callback to testMethod [#3853](https://github.com/storybooks/storybook/pull/3853)
#### Bug Fixes
- Fix getstorybook CLI [#4213](https://github.com/storybooks/storybook/pull/4213)
- FIX regression devtool, in case of cross domain parent, window.parent might throw [#4199](https://github.com/storybooks/storybook/pull/4199)
#### Dependency Upgrades
- Upgrade deps dealing with license issues [#4228](https://github.com/storybooks/storybook/pull/4228)
- Use @emotion/snapshot-serializer [#4206](https://github.com/storybooks/storybook/pull/4206)
# 4.0.0-alpha.22
2018-September-19
#### Features
- Storyshots: story params support [#4176](https://github.com/storybooks/storybook/pull/4176)
- Addon-options: story params support [#3965](https://github.com/storybooks/storybook/pull/3965)
- Presets - API generalization [#4173](https://github.com/storybooks/storybook/pull/4173)
- start-storybook: open browser tab on first compilation [#4149](https://github.com/storybooks/storybook/pull/4149)
- start-storybook: suggest an alternative when the port is occupied [#4146](https://github.com/storybooks/storybook/pull/4146)
- Merge webpack optimisation configs [#4121](https://github.com/storybooks/storybook/pull/4121)
#### Bug Fixes
- Angular cli - fix prebuild [#4187](https://github.com/storybooks/storybook/pull/4187)
- Presets - add babelDefault extension [#4155](https://github.com/storybooks/storybook/pull/4155)
- CHANGE index.html.ejs to use files over chunks && UPGRADE generate-page-webpack-plugin [#4134](https://github.com/storybooks/storybook/pull/4134)
- Allow replacing of stories (with warning rather than error) [#4061](https://github.com/storybooks/storybook/pull/4061)
#### Maintenance
- CLI refactor [#4168](https://github.com/storybooks/storybook/pull/4168)
- Fix linter warnings [#4172](https://github.com/storybooks/storybook/pull/4172)
- Remove gh-pages deploy in favor of netlify [#4128](https://github.com/storybooks/storybook/pull/4128)
#### Dependency Upgrades
- [core]: widen `airbnb-js-shims` dep range [#4189](https://github.com/storybooks/storybook/pull/4189)
- Updating react-split-pane to version 0.1.84 [#4153](https://github.com/storybooks/storybook/pull/4153)
- Riot tag loader missing in cli [#4122](https://github.com/storybooks/storybook/pull/4122)
# 3.4.11
2018-September-17
#### Dependencies
- Allow v1 or v2 in airbnb-js-shims [#4190](https://github.com/storybooks/storybook/pull/4190)
# 4.0.0-alpha.21
2018-September-07
@ -17,8 +206,8 @@
#### Other
- [WIP] Refactor core and frameworks to work with presets [#4043](https://github.com/storybooks/storybook/pull/4043)
- [WIP] presets - merge default babel configs [#4107](https://github.com/storybooks/storybook/pull/4107)
- \[WIP\] Refactor core and frameworks to work with presets [#4043](https://github.com/storybooks/storybook/pull/4043)
- \[WIP\] presets - merge default babel configs [#4107](https://github.com/storybooks/storybook/pull/4107)
# 4.0.0-alpha.20
@ -95,7 +284,7 @@ Not published to NPM
- Temp revert the 36a2676 [#4062](https://github.com/storybooks/storybook/pull/4062)
- Remove deprecation of --db-path and --enable-db [#4030](https://github.com/storybooks/storybook/pull/4030)
- Remove git info extraction [#4031](https://github.com/storybooks/storybook/pull/4031)
- Fixed homepage links [skip ci] [#4008](https://github.com/storybooks/storybook/pull/4008)
- Fixed homepage links \[skip ci\] [#4008](https://github.com/storybooks/storybook/pull/4008)
- CHANGE html-webpack-plugin for generate-page-plugin [#3919](https://github.com/storybooks/storybook/pull/3919)
# 4.0.0-alpha.16
@ -108,7 +297,7 @@ Not published to NPM
#### Bug Fixes
- [BUG FIX] Use fixed version of react-dev-utils [#3959](https://github.com/storybooks/storybook/pull/3959)
- \[BUG FIX\] Use fixed version of react-dev-utils [#3959](https://github.com/storybooks/storybook/pull/3959)
- Inline emotion css calls that require theme to avoid using state [#3950](https://github.com/storybooks/storybook/pull/3950)
#### Dependency Upgrades
@ -998,7 +1187,7 @@ Read on for more improvements, fixes, 1In addition, there are hundreds of depend
#### Bug Fixes
- [Addon-storyshots] Remove default options on "goto" call [#3298](https://github.com/storybooks/storybook/pull/3298)
- \[Addon-storyshots\] Remove default options on "goto" call [#3298](https://github.com/storybooks/storybook/pull/3298)
- CLI: add error handling for latest_version helper [#3297](https://github.com/storybooks/storybook/pull/3297)
- Refactor CLI to use `npm` and `yarn` instead of third party packages [#3275](https://github.com/storybooks/storybook/pull/3275)
- Fix issue when extending webpack config [#3279](https://github.com/storybooks/storybook/pull/3279)
@ -1058,7 +1247,7 @@ Read on for more improvements, fixes, 1In addition, there are hundreds of depend
#### Bug Fixes
- [Hotfix] Use published webpack 4 compatible fork of react-dev-utils [#3312](https://github.com/storybooks/storybook/pull/3312)
- \[Hotfix\] Use published webpack 4 compatible fork of react-dev-utils [#3312](https://github.com/storybooks/storybook/pull/3312)
# 4.0.0-alpha.0
@ -1085,7 +1274,7 @@ Read on for more improvements, fixes, 1In addition, there are hundreds of depend
#### Bug Fixes
- Update react-native symlink resolving and add support for flow [#3306](https://github.com/storybooks/storybook/pull/3306)
- [Addon-storyshots] Remove default options on "goto" call [#3298](https://github.com/storybooks/storybook/pull/3298)
- \[Addon-storyshots\] Remove default options on "goto" call [#3298](https://github.com/storybooks/storybook/pull/3298)
- Remove onDeviceUI animation to support Detox screenshots [#3272](https://github.com/storybooks/storybook/pull/3272)
- Angular: use resolveLoader from cliCommonConfig [#3251](https://github.com/storybooks/storybook/pull/3251)

View File

@ -60,13 +60,6 @@ You can also pick suites from CLI. Suites available are listed below.
This option executes test from `<rootdir>/app/react`, `<rootdir>/app/vue`, and `<rootdir>/lib`.
Before the tests are ran, the project must be bootstrapped with core. You can accomplish this with `yarn bootstrap --core`
##### React-Native example Tests
`yarn test --reactnative`
This option executes tests from `<rootdir>/app/react-native`.
Before these tests are ran, the project must be bootstrapped with the React Native example enabled. You can accomplish this by running `yarn bootstrap --reactnative`
##### CRA-kitchen-sink - Image snapshots using Storyshots
`yarn test --image`
@ -312,6 +305,14 @@ The current manual release sequence is as follows:
- Clean, build and publish the release
- Cut and paste the changelog to the github release page, and mark it as a (pre-) release
**NOTE:** The very first time you publish a scoped package (`@storybook/x`) you need to make sure that it's package.json contains the following
```js
"publishConfig": {
"access": "public"
}
```
This sequence applies to both releases and pre-releases, but differs slightly between the two.
**NOTE: This is a work in progress. Don't try this unless you know what you're doing. We hope to automate this in CI, so this process is designed with that in mind.**

54
MAINTAINERS.md Normal file
View File

@ -0,0 +1,54 @@
This document will document some of the processes that members of the documentation team should adhere to.
# PR Process
1. Triage with the correct [label](#labels)
2. If there a change related to it ensure it has been published and tested before closing
# Labels
| label name | purpose |
|:--------------:|:------------|
| accessibility | |
| addon:(name) | |
| app:(name) | |
| api:(name) | |
| cleanup | Minor cleanup style change that won't show up in release changelog |
| bug | |
| cli | |
| good first review | |
| compatibility with other tools | |
| patch | Bugfix & documentation PR that need to be picked to release branch |
| picked | Patch PRs cherry-picked to master |
| compatibility with other tools | |
| components | |
| core | |
| decorators | |
| dependencies:update | |
| dependencies | |
| discussion | |
| do not merge | |
| documentation | |
| feature request | |
| good first issue | |
| has workaround | |
| help wanted | |
| high priority | |
| in progress | |
| inactive | |
| maintenance | |
| merged | |
| needs example | |
| needs more info | |
| needs rebase | |
| needs reproduction | |
| needs review | |
| performance issue | |
| presets | |
| question / support | |
| ready | |
| security | |
| todo | |
| typescript | |
| ui | |
| won't fix | |

View File

@ -3,12 +3,16 @@
## Table of contents
- [From version 3.4.x to 4.0.x](#from-version-34x-to-40x)
- [React 16.3](#react-163)
- [Keyboard shortcuts moved](#keyboard-shortcuts-moved)
- [Removed addWithInfo](#removed-add-with-info)
- [Removed RN packager](#removed-rn-packager)
- [Removed RN addons](#removed-rn-addons)
- [Storyshots changes](#storyshots-changes)
- [Webpack 4](#webpack-4)
- [Babel 7](#babel-7)
- [Create-react-app](#create-react-app)
- [CLI rename](#cli-rename)
- [From version 3.3.x to 3.4.x](#from-version-33x-to-34x)
- [From version 3.2.x to 3.3.x](#from-version-32x-to-33x)
- [Refactored Knobs](#refactored-knobs)
@ -24,9 +28,35 @@
- [Packages renaming](#packages-renaming)
- [Deprecated embedded addons](#deprecated-embedded-addons)
## From 3.4.x to 4.0
## From version 3.4.x to 4.0.x
With 4.0 as our first major release in over a year, we've collected a lot of cleanup tasks. All deprecations have been marked for months, so we hope that there will be no significant impact on your project.
With 4.0 as our first major release in over a year, we've collected a lot of cleanup tasks. Most of the deprecations have been marked for months, so we hope that there will be no significant impact on your project.
### React 16.3+
Storybook uses [Emotion](https://emotion.sh/) for styling which currently requires React 16.3 and above.
If you're using Storybook for anything other than React, you probably don't need to worry about this.
However, if you're developing React components, this means you need to upgrade to 16.3 or higher to use Storybook 4.0.
> **NOTE:** This is a temporary requirement, and we plan to restore 15.x compatibility in a near-term 4.x release.
Also, here's the error you'll get if you're running an older version of React:
```
core.browser.esm.js:15 Uncaught TypeError: Object(...) is not a function
at Module../node_modules/@emotion/core/dist/core.browser.esm.js (core.browser.esm.js:15)
at __webpack_require__ (bootstrap:724)
at fn (bootstrap:101)
at Module../node_modules/@emotion/styled-base/dist/styled-base.browser.esm.js (styled-base.browser.esm.js:1)
at __webpack_require__ (bootstrap:724)
at fn (bootstrap:101)
at Module../node_modules/@emotion/styled/dist/styled.esm.js (styled.esm.js:1)
at __webpack_require__ (bootstrap:724)
at fn (bootstrap:101)
at Object../node_modules/@storybook/components/dist/navigation/MenuLink.js (MenuLink.js:12)
```
### Generic addons
@ -46,6 +76,12 @@ import { number } from "@storybook/addon-knobs";
4.0 also reversed the order of addon-knob's `select` knob keys/values, which had been called `selectV2` prior to this breaking change. See the knobs [package README](https://github.com/storybooks/storybook/blob/master/addons/knobs/README.md#select) for usage.
### Knobs URL parameters
Addon-knobs no longer updates the URL parameters interactively as you edit a knob. This is a UI change but it shouldn't break any code because old URLs are still supported.
In 3.x, editing knobs updated the URL parameters interactively. The implementation had performance and architectural problems. So in 4.0, we changed this to a "copy" button tp the addon which generates a URL with the updated knob values and copies it to the clipboard.
### Keyboard shortcuts moved
- Addon Panel to `Z`
@ -57,6 +93,14 @@ import { number } from "@storybook/addon-knobs";
`Addon-info`'s `addWithInfo` has been marked deprecated since 3.2. In 4.0 we've removed it completely. See the package [README](https://github.com/storybooks/storybook/blob/master/addons/info/README.md) for the proper usage.
### Removed RN packager
Since storybook version v4.0 packager is removed from storybook. The suggested storybook usage is to include it inside your app.
If you want to keep the old behaviour, you have to start the packager yourself with a different project root.
`npm run storybook start -p 7007 | react-native start --projectRoot storybook`
Removed cli options: `--packager-port --root --projectRoots -r, --reset-cache --skip-packager --haul --platform --metro-config`
### Removed RN addons
The `@storybook/react-native` had built-in addons (`addon-actions` and `addon-links`) that have been marked as deprecated since 3.x. They have been fully removed in 4.x. If your project still uses the built-ins, you'll need to add explicit dependencies on `@storybook/addon-actions` and/or `@storybook/addon-links` and import directly from those packages.
@ -82,11 +126,55 @@ Storybook now uses webpack 4. If you have a [custom webpack config](https://stor
Storybook now uses Babel 7. There's a couple of cases when it can break with your app:
* If you aren't using Babel yourself, and don't have .babelrc, install following dependencies:
```
npm i -D @babel/core babel-loader@next
```
* If you're using Babel 6, make sure that you have direct dependencies on `babel-core@6` and `babel-loader@7`.
- If you aren't using Babel yourself, and don't have .babelrc, install following dependencies:
```
npm i -D @babel/core babel-loader@next
```
- If you're using Babel 6, make sure that you have direct dependencies on `babel-core@6` and `babel-loader@7` and that you have a `.babelrc` in your project directory.
### Create-react-app
If you are using `create-react-app` (aka CRA), you may need to do some manual steps to upgrade, depending on the setup.
- `create-react-app@1` may require manual migrations.
- If you're adding storybook for the first time, it should just work: `sb init` should add the correct dependencies.
- If you've upgrading an existing project, your `package.json` probably already uses Babel 6, making it incompatible with `@storybook/react@4` which uses Babel 7. There are two ways to make it compatible, each of which is spelled out in detail in the next section:
- Upgrade to Babel 7 if you are not dependent on Babel 6-specific features.
- Migrate Babel 6 if you're heavily dependent on some Babel 6-specific features).
- `create-react-app@2` should be compatible as is, since it uses babel 7.
#### Upgrade CRA1 to babel 7
```
yarn remove babel-core babel-runtime
yarn add @babel/core babel-loader --dev
```
#### Migrate CRA1 while keeping babel 6
```
yarn add babel-loader@7
```
Also make sure you have a `.babelrc` in your project directory. You probably already do if you are using Babel 6 features (otherwise you should consider upgrading to Babel 7 instead). If you don't have one, here's a simple one that works:
```json
{
"presets": ["env", "react"]
}
```
### start-storybook opens browser automatically
If you're using `start-storybook` on CI, you may need to opt out of this using the new `--ci` flag.
### CLI Rename
We've deprecated the `getstorybook` CLI in 4.0. The new way to install storybook is `sb init`. We recommend using `npx` for convenience and to make sure you're always using the latest version of the CLI:
```
npx -p @storybook/cli@rc sb init
```
## From version 3.3.x to 3.4.x
@ -203,7 +291,7 @@ To update your app to use the new package names, you can use the cli:
npm install --global @storybook/cli
# if you run this inside a v2 app, it should perform the necessary codemods.
getstorybook
storybook init
```
#### Details

153
README.md
View File

@ -10,21 +10,24 @@
[![Backers on Open Collective](https://opencollective.com/storybook/backers/badge.svg)](#backers)
[![Sponsors on Open Collective](https://opencollective.com/storybook/sponsors/badge.svg)](#sponsors)
[![License](https://img.shields.io/github/license/storybooks/storybook.svg)](https://github.com/storybooks/storybook/blob/master/LICENSE)
<!-- [![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=<badge_key>)](https://www.browserstack.com/automate/public-build/<badge_key>) -->
* * *
---
Storybook is a development environment for UI components.
It allows you to browse a component library, view the different states of each component, and interactively develop and test components.
## Intro
![Storybook Screenshot](media/storybook-intro.gif)
<center>
<img src="media/storybook-intro.gif" width="100%" />
</center>
README for:
- [![Alpha](https://img.shields.io/npm/v/@storybook/core/alpha.svg)](https://github.com/storybooks/storybook)
- [![Latest](https://img.shields.io/npm/v/@storybook/core/latest.svg)](https://github.com/storybooks/storybook/tree/release/3.4)
- [![Alpha](https://img.shields.io/npm/v/@storybook/core/alpha.svg)](https://github.com/storybooks/storybook)
- [![Latest](https://img.shields.io/npm/v/@storybook/core/latest.svg)](https://github.com/storybooks/storybook/tree/release/3.4)
Storybook runs outside of your app. This allows you to develop UI components in isolation, which can improve component reuse, testability, and development speed. You can build quickly without having to worry about application-specific dependencies.
@ -34,38 +37,36 @@ Storybook comes with a lot of [addons](https://storybook.js.org/addons/introduct
## Table of contents
- [Getting Started](#getting-started)
- [Projects](#projects)
- [Supported Frameworks](#supported-frameworks)
- [Sub Projects](#sub-projects)
- [Addons](#addons)
- [Live Examples](#live-examples) 💪
- [Badges](#badges)
- [Contributing](#contributing)
- [Development scripts](#development-scripts)
- [Backers](#backers)
- [Sponsors](#sponsors)
- 🚀[Getting Started](#getting-started)
- 📒[Projects](#projects)
- 🛠[Supported Frameworks & Examples](#supported-frameworks)
- 🚇[Sub Projects](#sub-projects)
- 🔗[Addons](#addons)
- 🏅[Badges & Presentation materials](#badges--presentation-materials)
- 👥[Community](#community)
- 👏[Contributing](#contributing)
- 👨‍💻[Development scripts](#development-scripts)
- 💵[Backers](#backers)
- 💸[Sponsors](#sponsors)
## Getting Started
First install storybook:
```sh
npm i -g @storybook/cli
cd my-react-app
getstorybook
npx -p @storybook/cli@rc sb init
```
The `-g` global install is used to run our cli tool in your project directory to generate templates for your existing projects. To avoid the global install and start your project manually, take a look at our [Slow Start Guide](https://storybook.js.org/basics/slow-start-guide/).
If you'd rather set up your project manually, take a look at our [Slow Start Guide](https://storybook.js.org/basics/slow-start-guide/).
Once it's installed, you can `npm run storybook` and it will run the development server on your local machine, and give you a URL to browse some sample stories.
**Storybook v2.x migration note**: If you're using Storybook v2.x and want to shift to 3.x version the easiest way is:
**Storybook v2.x migration note**: If you're using Storybook v2.x and want to shift to 4.x version the easiest way is:
```sh
npm i -g @storybook/cli
cd my-storybook-v2-app
getstorybook
npx -p @storybook/cli@rc sb init
```
It runs a codemod to update all package names. Read all migration details in our [Migration Guide](MIGRATION.md)
@ -78,69 +79,49 @@ For additional help, join us [in our Slack](https://now-examples-slackin-rrirkqo
### Supported Frameworks
- [React](app/react) [![React](https://img.shields.io/npm/dt/@storybook/react.svg)](app/react)
- [React Native](app/react-native) [![React Native](https://img.shields.io/npm/dt/@storybook/react-native.svg)](app/react-native)
- [Vue](app/vue) [![Vue](https://img.shields.io/npm/dt/@storybook/vue.svg)](app/vue)
- [Angular](app/angular) [![Angular](https://img.shields.io/npm/dt/@storybook/angular.svg)](app/angular)
- [Polymer](app/polymer) [![Polymer](https://img.shields.io/npm/dt/@storybook/polymer.svg)](app/polymer)
- [Mithril](app/mithril) <sup>alpha</sup> [![Mithril](https://img.shields.io/npm/dt/@storybook/mithril.svg)](app/mithril)
- [Marko](app/marko) <sup>alpha</sup> [![Marko](https://img.shields.io/npm/dt/@storybook/marko.svg)](app/marko)
- [HTML](app/html) <sup>alpha</sup> [![HTML](https://img.shields.io/npm/dt/@storybook/html.svg)](app/html)
- [Svelte](app/svelte) <sup>alpha</sup> [![Svelte](https://img.shields.io/npm/dt/@storybook/svelte.svg)](app/svelte)
- [Riot](app/riot) <sup>alpha</sup> [![Riot](https://img.shields.io/npm/dt/@storybook/riot.svg)](app/riot)
| Framework | Demo latest | Demo prerelease | |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| [React](app/react) | [v3.4.x](https://release-3-4--storybooks-official.netlify.com), [v3.3.x](https://release-3-3--storybooks-official.netlify.com) | [v4.0.0-alpha](https://storybooks-official.netlify.com) | [![React](https://img.shields.io/npm/dt/@storybook/react.svg)](app/react) |
| [React Native](app/react-native) | - | - | [![React Native](https://img.shields.io/npm/dt/@storybook/react-native.svg)](app/react-native) |
| [Vue](app/vue) | [v3.4.x](https://release-3-4--storybooks-vue.netlify.com/), [v3.3.x](https://release-3-3--storybooks-vue.netlify.com/) | [v4.0.0-alpha](https://storybooks-vue.netlify.com/) | [![Vue](https://img.shields.io/npm/dt/@storybook/vue.svg)](app/vue) |
| [Angular](app/angular) | [v3.4.x](https://release-3-4--storybooks-angular.netlify.com/), [v3.3.x](https://release-3-3--storybooks-angular.netlify.com/) | [v4.0.0-alpha](https://storybooks-angular.netlify.com/) | [![Angular](https://img.shields.io/npm/dt/@storybook/angular.svg)](app/angular) |
| [Polymer](app/polymer) | [v3.4.x](https://release-3-4--storybooks-polymer.netlify.com/) | [v4.0.0-alpha](https://storybooks-polymer.netlify.com/) | [![Polymer](https://img.shields.io/npm/dt/@storybook/polymer.svg)](app/polymer) |
| [Mithril](app/mithril) <sup>alpha</sup> | - | [v4.0.0-alpha](https://storybooks-mithril.netlify.com/) | [![Mithril](https://img.shields.io/npm/dt/@storybook/mithril.svg)](app/mithril) |
| [Marko](app/marko) <sup>alpha</sup> | - | [v4.0.0-alpha](https://storybooks-marko.netlify.com/) | [![Marko](https://img.shields.io/npm/dt/@storybook/marko.svg)](app/marko) |
| [HTML](app/html) <sup>alpha</sup> | - | [v4.0.0-alpha](https://storybooks-html.netlify.com/) | [![HTML](https://img.shields.io/npm/dt/@storybook/html.svg)](app/html) |
| [Svelte](app/svelte) <sup>alpha</sup> | - | [v4.0.0-alpha](https://storybooks-svelte.netlify.com/) | [![Svelte](https://img.shields.io/npm/dt/@storybook/svelte.svg)](app/svelte) |
| [Riot](app/riot) <sup>alpha</sup> | - | [v4.0.0-alpha](https://storybooks-riot.netlify.com/) | [![Riot](https://img.shields.io/npm/dt/@storybook/riot.svg)](app/riot) |
| [Ember](app/ember) <sup>alpha</sup> | - | [v4.0.0-alpha](https://storybooks-ember.netlify.com/) | [![Ember](https://img.shields.io/npm/dt/@storybook/ember.svg)](app/ember) |
### Sub Projects
- [CLI](lib/cli) - Streamlined installation for a variety of app types
- [examples](examples) - Code examples to illustrate different Storybook use cases
- [CLI](lib/cli) - Streamlined installation for a variety of app types
- [examples](examples) - Code examples to illustrate different Storybook use cases
### Addons
- [a11y](addons/a11y/) - Test components for user accessibility in Storybook
- [actions](addons/actions/) - Log actions as users interact with components in the Storybook UI
- [backgrounds](addons/backgrounds/) - Let users choose backgrounds in the Storybook UI
- [centered](addons/centered/) - Center the alignment of your components within the Storybook UI
- [events](addons/events/) - Interactively fire events to components that respond to EventEmitter
- [graphql](addons/graphql/) - Query a GraphQL server within Storybook stories
- [info](addons/info/) - Annotate stories with extra component usage information
- [jest](addons/jest/) - View the results of components' unit tests in Storybook
- [knobs](addons/knobs/) - Interactively edit component prop data in the Storybook UI
- [links](addons/links/) - Create links between stories
- [notes](addons/notes/) - Annotate Storybook stories with notes
- [options](addons/options/) - Customize the Storybook UI in code
- [storyshots](addons/storyshots/) - Easy snapshot testing for components in Storybook
- [storysource](addons/storysource/) - View the code of your stories within the Storybook UI
- [viewport](addons/viewport/) - Change display sizes and layouts for responsive components using Storybook
| Addons | |
| ------------------------------------------- | -------------------------------------------------------------------------- |
| [a11y](addons/a11y/) | Test components for user accessibility in Storybook |
| [actions](addons/actions/) | Log actions as users interact with components in the Storybook UI |
| [backgrounds](addons/backgrounds/) | Let users choose backgrounds in the Storybook UI |
| [centered](addons/centered/) | Center the alignment of your components within the Storybook UI |
| [events](addons/events/) | Interactively fire events to components that respond to EventEmitter |
| [graphql](addons/graphql/) | Query a GraphQL server within Storybook stories |
| [google-analytics](addons/google-analytics) | Reports google analytics on stories |
| [info](addons/info/) | Annotate stories with extra component usage information |
| [jest](addons/jest/) | View the results of components' unit tests in Storybook |
| [knobs](addons/knobs/) | Interactively edit component prop data in the Storybook UI |
| [links](addons/links/) | Create links between stories |
| [notes](addons/notes/) | Annotate Storybook stories with notes |
| [options](addons/options/) | Customize the Storybook UI in code |
| [storyshots](addons/storyshots/) | Easy snapshot testing for components in Storybook |
| [storysource](addons/storysource/) | View the code of your stories within the Storybook UI |
| [viewport](addons/viewport/) | Change display sizes and layouts for responsive components using Storybook |
See [Addon / Framework Support Table](ADDONS_SUPPORT.md)
## Live Examples
### 4.0.alpha
> Note, this is an Alpha version which may not be well tested. Features in this version are not final.
- [React Official](https://storybooks-official.netlify.com)
- [Vue](https://storybooks-vue.netlify.com/)
- [Angular](https://storybooks-angular.netlify.com/)
- [Polymer](https://storybooks-polymer.netlify.com/)
- [Mithril](https://storybooks-mithril.netlify.com/)
- [Marko](https://storybooks-marko.netlify.com/)
- [HTML](https://storybooks-html.netlify.com/)
- [Svelte](https://storybooks-svelte.netlify.com/)
- [Riot](https://storybooks-riot.netlify.com/)
### 3.4
- [React Official](https://release-3-4--storybooks-official.netlify.com)
- [Vue](https://release-3-4--storybooks-vue.netlify.com/)
- [Angular](https://release-3-4--storybooks-angular.netlify.com/)
- [Polymer](https://release-3-4--storybooks-polymer.netlify.com/)
### 3.3
- [React Official](https://release-3-3--storybooks-official.netlify.com)
- [Vue](https://release-3-3--storybooks-vue.netlify.com/)
- [Angular](https://release-3-3--storybooks-angular.netlify.com/)
## Badges
## Badges & Presentation materials
We have a badge ! Link it to your live Storybook example.
@ -150,14 +131,24 @@ We have a badge ! Link it to your live Storybook example.
[![Storybook](https://github.com/storybooks/press/blob/master/badges/storybook.svg)](link to site)
```
If you're looking for material to use in your presentation about storybook, like logo's video material and the colors we use etc, you can find all of that at our [press repo](https://github.com/storybooks/press).
## Community
- Tweeting via [@storybookjs](https://twitter.com/storybookjs)
- Blogging at [Medium](https://medium.com/storybookjs)
- Chatting on [Slack](https://now-examples-slackin-rrirkqohko.now.sh/)
- Discussions on [Discord](https://discord.gg/sMFvFsG)
- Streaming saved at [Youtube](https://www.youtube.com/channel/UCr7Quur3eIyA_oe8FNYexfg)
## Contributing
[![Good First Issue](https://img.shields.io/github/issues/storybooks/storybook/good%20first%20issue.svg)](https://github.com/storybooks/storybook/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
We welcome contributions to Storybook!
- ⇄ Pull requests and ★ Stars are always welcome.
- Read our [contributing guide](CONTRIBUTING.md) to get started.
- ⇄ Pull requests and ★ Stars are always welcome.
- Read our [contributing guide](CONTRIBUTING.md) to get started.
### Development scripts
@ -174,16 +165,16 @@ We welcome contributions to Storybook!
> boolean check if code conforms to linting rules - uses remark & eslint
- `yarn lint:js` - will check js
- `yarn lint:md` - will check markdown + code samples
- `yarn lint:js` - will check js
- `yarn lint:md` - will check markdown + code samples
- `yarn lint:js --fix` - will automatically fix js
- `yarn lint:js --fix` - will automatically fix js
#### `yarn test`
> boolean check if unit tests all pass - uses jest
- `yarn run test --core --watch` - will run core tests in watch-mode
- `yarn run test --core --watch` - will run core tests in watch-mode
### Sponsors

View File

@ -11,7 +11,6 @@
* [Supporting other frameworks and libraries](#supporting-other-frameworks-and-libraries)
+ [Polymer & Webcomponents](#polymer---webcomponents)
+ [Aurelia](#aurelia)
+ [Ember](#ember)
* [Breaking changes](#breaking-changes)
+ [Addon API](#addon-api)
+ [API for adding stories](#api-for-adding-stories)
@ -69,10 +68,6 @@ Storybook for Polymer is currently in development, and will support custom eleme
We're reaching out to the Aurelia maintainers to cooperate on this.
### Ember
We're reaching out to the Ember maintainers to cooperate on this.
## Breaking changes
### Addon API
@ -92,7 +87,7 @@ We have a new logo, so next step is a overhaul of our documentation site.
### Record videos and write blog post on how to use, tweak & develop storybook
- writing addons,
- writing addons,
- choosing the right addons.
- how to start developing on our codebase.
- how to use storybook itself and the CLI.

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-a11y",
"version": "4.0.0-alpha.21",
"version": "4.0.0-rc.1",
"description": "a11y addon for storybook",
"keywords": [
"a11y",
@ -11,6 +11,9 @@
"verify"
],
"homepage": "https://github.com/storybooks/storybook#readme",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -25,12 +28,12 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@emotion/styled": "0.10.5",
"@storybook/addons": "4.0.0-alpha.21",
"@storybook/client-logger": "4.0.0-alpha.21",
"@storybook/components": "4.0.0-alpha.21",
"@storybook/core-events": "4.0.0-alpha.21",
"axe-core": "^3.0.3",
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.0-rc.1",
"@storybook/client-logger": "4.0.0-rc.1",
"@storybook/components": "4.0.0-rc.1",
"@storybook/core-events": "4.0.0-rc.1",
"axe-core": "^3.1.2",
"global": "^4.3.2",
"prop-types": "^15.6.2"
},

View File

@ -19,6 +19,12 @@ const Violations = styled.span(({ theme }) => ({
color: theme.failColor,
}));
const PanelWrapper = styled.div({
height: '100%',
overflow: 'auto',
width: '100%',
});
class Panel extends Component {
static propTypes = {
active: PropTypes.bool.isRequired,
@ -78,7 +84,7 @@ class Panel extends Component {
const { active } = this.props;
return active ? (
<div>
<PanelWrapper>
<Tabs
tabs={[
{
@ -94,7 +100,7 @@ class Panel extends Component {
<ActionBar>
<ActionButton onClick={this.requestCheck}>RERUN TEST</ActionButton>
</ActionBar>
</div>
</PanelWrapper>
) : null;
}
}

View File

@ -1,11 +1,14 @@
{
"name": "@storybook/addon-actions",
"version": "4.0.0-alpha.21",
"version": "4.0.0-rc.1",
"description": "Action Logger addon for storybook",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/actions",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -20,15 +23,15 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@emotion/core": "^0.13.0",
"@emotion/provider": "0.11.1",
"@emotion/styled": "0.10.5",
"@storybook/addons": "4.0.0-alpha.21",
"@storybook/components": "4.0.0-alpha.21",
"@storybook/core-events": "4.0.0-alpha.21",
"@emotion/core": "^0.13.1",
"@emotion/provider": "^0.11.2",
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.0-rc.1",
"@storybook/components": "4.0.0-rc.1",
"@storybook/core-events": "4.0.0-rc.1",
"deep-equal": "^1.0.1",
"global": "^4.3.2",
"lodash.isequal": "^4.5.0",
"lodash": "^4.17.11",
"make-error": "^1.3.5",
"prop-types": "^15.6.2",
"react-inspector": "^2.3.0",

View File

@ -38,5 +38,5 @@ export const Wrapper = styled.div({
flex: 1,
display: 'flex',
position: 'relative',
minHeight: '100%',
height: '100%',
});

View File

@ -1,6 +1,6 @@
// Based on http://backbonejs.org/docs/backbone.html#section-164
import { document, Element } from 'global';
import isEqual from 'lodash.isequal';
import isEqual from 'lodash/isEqual';
import addons from '@storybook/addons';
import Events from '@storybook/core-events';

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-backgrounds",
"version": "4.0.0-alpha.21",
"version": "4.0.0-rc.1",
"description": "A storybook addon to show different backgrounds for your preview",
"keywords": [
"addon",
@ -8,7 +8,10 @@
"react",
"storybook"
],
"homepage": "https://storybook.js.org",
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/backgrounds",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -24,16 +27,13 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@emotion/styled": "0.10.5",
"@storybook/addons": "4.0.0-alpha.21",
"@storybook/core-events": "4.0.0-alpha.21",
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.0-rc.1",
"@storybook/core-events": "4.0.0-rc.1",
"global": "^4.3.2",
"prop-types": "^15.6.2",
"util-deprecate": "^1.0.2"
},
"devDependencies": {
"vue": "^2.5.17"
},
"peerDependencies": {
"react": "*"
}

1
addons/centered/ember.js Normal file
View File

@ -0,0 +1 @@
module.exports = require('./dist/ember');

View File

@ -1,7 +1,22 @@
{
"name": "@storybook/addon-centered",
"version": "4.0.0-alpha.21",
"version": "4.0.0-rc.1",
"description": "Storybook decorator to center components",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/centered",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git"
},
"license": "MIT",
"author": "Muhammed Thanish <mnmtanish@gmail.com>",
"main": "dist/index.js",

View File

@ -0,0 +1,25 @@
import { document } from 'global';
import styles from './styles';
export default function(storyFn) {
const { template, context } = storyFn();
const element = document.createElement('div');
Object.assign(element.style, styles.style);
const innerElement = document.createElement('div');
Object.assign(innerElement.style, styles.innerStyle);
element.appendChild(innerElement);
// the inner element should append the parent
innerElement.appendTo = function appendTo(el) {
el.appendChild(element);
};
return {
template,
context,
element: innerElement,
};
}

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-events",
"version": "4.0.0-alpha.21",
"version": "4.0.0-rc.1",
"description": "Add events to your Storybook stories.",
"keywords": [
"addon",
@ -8,9 +8,16 @@
"react",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/events",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
"repository": {
"type": "git",
"url": "git@github.com:storybooks/storybook.git"
"url": "https://github.com/storybooks/storybook.git"
},
"license": "MIT",
"main": "dist/index.js",
@ -19,9 +26,9 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@emotion/styled": "0.10.5",
"@storybook/addons": "4.0.0-alpha.21",
"@storybook/core-events": "4.0.0-alpha.21",
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.0-rc.1",
"@storybook/core-events": "4.0.0-rc.1",
"format-json": "^1.0.3",
"prop-types": "^15.6.2",
"react-lifecycles-compat": "^3.0.4",

View File

@ -0,0 +1,25 @@
# Storybook Addon Google Analytics
Storybook Addon Google Analytics can be used to support google analytics in [Storybook](https://storybook.js.org).
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)
## Getting Started
Install:
```sh
npm i -D @storybook/addon-google-analytics
```
Then, add following content to `.storybook/addons.js`
```js
import '@storybook/addon-google-analytics/register';
```
Then, set an environment variable
```
window.STORYBOOK_GA_ID = UA-000000-01
```

View File

@ -0,0 +1,31 @@
{
"name": "@storybook/addon-google-analytics",
"version": "4.0.0-rc.1",
"description": "Storybook addon for google analytics",
"keywords": [
"addon",
"storybook"
],
"publishConfig": {
"access": "public"
},
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/google-analytics",
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git"
},
"license": "MIT",
"main": "dist/index.js",
"jsnext:main": "src/index.js",
"scripts": {
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.0-rc.1",
"global": "^4.3.2",
"react-ga": "^2.5.3"
}
}

View File

@ -0,0 +1 @@
export default {};

View File

@ -0,0 +1,17 @@
import addons from '@storybook/addons';
import { window } from 'global';
import ReactGA from 'react-ga';
addons.register('storybook/google-analytics', api => {
ReactGA.initialize(window.STORYBOOK_GA_ID);
api.onStory((kind, story) => {
let path = window.location.pathname;
if (path === '/') {
path = '';
}
ReactGA.pageview(`${path}/${kind}/${story}`);
});
});

View File

@ -1,11 +1,15 @@
{
"name": "@storybook/addon-graphql",
"version": "4.0.0-alpha.21",
"version": "4.0.0-rc.1",
"description": "Storybook addon to display the GraphiQL IDE",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/graphql",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -21,8 +25,8 @@
},
"dependencies": {
"global": "^4.3.2",
"graphiql": "^0.11.11",
"graphql": "^0.13.2",
"graphiql": "^0.12.0",
"graphql": "^14.0.2",
"prop-types": "^15.6.2"
},
"peerDependencies": {

View File

@ -1,7 +1,18 @@
{
"name": "@storybook/addon-info",
"version": "4.0.0-alpha.21",
"version": "4.0.0-rc.1",
"description": "A Storybook addon to show additional information for your stories.",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/info",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git"
@ -13,13 +24,13 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@emotion/styled": "0.10.5",
"@storybook/addons": "4.0.0-alpha.21",
"@storybook/client-logger": "4.0.0-alpha.21",
"@storybook/components": "4.0.0-alpha.21",
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.0-rc.1",
"@storybook/client-logger": "4.0.0-rc.1",
"@storybook/components": "4.0.0-rc.1",
"core-js": "2.5.7",
"global": "^4.3.2",
"marksy": "^6.0.3",
"marksy": "^6.1.0",
"nested-object-assign": "^1.0.1",
"prop-types": "^15.6.2",
"react-addons-create-fragment": "^15.5.3",
@ -27,7 +38,7 @@
"util-deprecate": "^1.0.2"
},
"devDependencies": {
"react-test-renderer": "^16.4.2"
"react-test-renderer": "^16.5.2"
},
"peerDependencies": {
"react": "*"

View File

@ -1,6 +1,63 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`addon Info should render <Info /> and external markdown 1`] = `
.emotion-4 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
font-size: .88em;
font-family: Menlo,Monaco,"Courier New",monospace;
background-color: #fafafa;
padding: .5rem;
line-height: 1.5;
overflow-x: scroll;
}
.emotion-2 {
overflow: hidden;
border: 1px solid #eee;
border-radius: 3px;
background-color: #FFFFFF;
cursor: pointer;
font-size: 13px;
padding: 3px 10px;
-webkit-align-self: flex-start;
-ms-flex-item-align: start;
align-self: flex-start;
-webkit-flex-shrink: 0;
-ms-flex-negative: 0;
flex-shrink: 0;
}
.emotion-2:hover {
background-color: #f4f7fa;
border-color: #ddd;
}
.emotion-2:active {
background-color: #e9ecef;
border-color: #ccc;
}
.emotion-0 {
-webkit-transition: -webkit-transform .2s ease;
-webkit-transition: transform .2s ease;
transition: transform .2s ease;
height: 16px;
-webkit-transform: translateY(-100%) translateY(-6px);
-ms-transform: translateY(-100%) translateY(-6px);
transform: translateY(-100%) translateY(-6px);
}
<deprecated>
<Story
PropTable={[Function]}
@ -1262,6 +1319,63 @@ exports[`addon Info should render <Info /> and external markdown 1`] = `
`;
exports[`addon Info should render <Info /> and markdown 1`] = `
.emotion-4 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
font-size: .88em;
font-family: Menlo,Monaco,"Courier New",monospace;
background-color: #fafafa;
padding: .5rem;
line-height: 1.5;
overflow-x: scroll;
}
.emotion-2 {
overflow: hidden;
border: 1px solid #eee;
border-radius: 3px;
background-color: #FFFFFF;
cursor: pointer;
font-size: 13px;
padding: 3px 10px;
-webkit-align-self: flex-start;
-ms-flex-item-align: start;
align-self: flex-start;
-webkit-flex-shrink: 0;
-ms-flex-negative: 0;
flex-shrink: 0;
}
.emotion-2:hover {
background-color: #f4f7fa;
border-color: #ddd;
}
.emotion-2:active {
background-color: #e9ecef;
border-color: #ccc;
}
.emotion-0 {
-webkit-transition: -webkit-transform .2s ease;
-webkit-transition: transform .2s ease;
transition: transform .2s ease;
height: 16px;
-webkit-transform: translateY(-100%) translateY(-6px);
-ms-transform: translateY(-100%) translateY(-6px);
transform: translateY(-100%) translateY(-6px);
}
<deprecated>
<Story
PropTable={[Function]}

View File

@ -26,47 +26,47 @@ Array [
`;
exports[`PropTable multiLineText should include all propTypes by default 1`] = `
<ForwardRef>
<Table>
<thead>
<tr>
<ForwardRef
<Th
bordered={true}
>
property
</ForwardRef>
<ForwardRef
</Th>
<Th
bordered={true}
>
propType
</ForwardRef>
<ForwardRef
</Th>
<Th
bordered={true}
>
required
</ForwardRef>
<ForwardRef
</Th>
<Th
bordered={true}
>
default
</ForwardRef>
<ForwardRef
</Th>
<Th
bordered={true}
>
description
</ForwardRef>
</Th>
</tr>
</thead>
<tbody>
<tr
key="foo"
>
<ForwardRef
<Td
bordered={true}
code={true}
>
foo
</ForwardRef>
<ForwardRef
</Td>
<Td
bordered={true}
code={true}
>
@ -78,21 +78,21 @@ exports[`PropTable multiLineText should include all propTypes by default 1`] = `
}
}
/>
</ForwardRef>
<ForwardRef
</Td>
<Td
bordered={true}
>
-
</ForwardRef>
<ForwardRef
</Td>
<Td
bordered={true}
>
-
</ForwardRef>
<ForwardRef
</Td>
<Td
bordered={true}
/>
</tr>
</tbody>
</ForwardRef>
</Table>
`;

View File

@ -1,5 +1,4 @@
/* eslint-disable no-underscore-dangle */
/* eslint-disable no-underscore-dangle,react/forbid-foreign-prop-types */
import PropTypes from 'prop-types';
import React from 'react';

View File

@ -42,7 +42,7 @@ but this can mean you'll experience merge conflicts on this file in the future.
## Generating the test results
You need to make sure the generated test-restuls file exists before you start storybook.
You need to make sure the generated test-results file exists before you start storybook.
During development you will likely start jest in watch-mode
and so the json file will be re-generated every time code or tests change.
@ -52,7 +52,7 @@ npm run test:generate-output -- --watch
This change will then be HMR (hot module reloaded) using webpack and displayed by this addon.
If you want to pre-run jest automaticly during development or a static build,
If you want to pre-run jest automatically during development or a static build,
you may need to consider that if your tests fail, the script receives a non-0 exit code and will exit.
You could create a `prebuild:storybook` npm script, which will never fail by appending `|| true`:
@ -77,7 +77,7 @@ import '@storybook/addon-jest/register';
## Usage
Assuming that you have created a test files `MyComponent.test.js` and `MyOtherComponent.test.js`
Assuming that you have created test files `MyComponent.test.js` and `MyOtherComponent.test.js`
In your `story.js`
@ -136,15 +136,15 @@ storiesOf('MyComponent', module).add('Story', () => <div>Jest results disabled h
### withTests(options)
- **options.results**: OBJECT jest output results. _mandatory_
- **filesExt**: STRING test file extention. _optional_. This allow you to write "MyComponent" and not "MyComponent.test.js". It will be used as regex to find your file results. Default value is `((\\.specs?)|(\\.tests?))?(\\.js)?$`. That mean it will match: MyComponent.js, MyComponent.test.js, MyComponent.tests.js, MyComponent.spec.js, MyComponent.specs.js...
- **filesExt**: STRING test file extension. _optional_. This allows you to write "MyComponent" and not "MyComponent.test.js". It will be used as regex to find your file results. Default value is `((\\.specs?)|(\\.tests?))?(\\.js)?$`. That means it will match: MyComponent.js, MyComponent.test.js, MyComponent.tests.js, MyComponent.spec.js, MyComponent.specs.js...
## Usage with Angular
Assuming that you have created a test files `my.component.spec.ts` and `my-other.comonent.spec.ts`
Assuming that you have created test files `my.component.spec.ts` and `my-other.comonent.spec.ts`
Configure Jest with [jest-preset-angular](https://www.npmjs.com/package/jest-preset-angular)
In project`s`typings.d.ts` add
In project's `typings.d.ts` add
```ts
declare module '*.json' {

View File

@ -1,6 +1,6 @@
{
"name": "@storybook/addon-jest",
"version": "4.0.0-alpha.21",
"version": "4.0.0-rc.1",
"description": "React storybook addon that show component jest report",
"keywords": [
"addon",
@ -11,11 +11,16 @@
"storybook",
"unit-testing"
],
"homepage": "https://storybook.js.org",
"bugs": "https://github.com/storybooks/storybook",
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/jest",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/storybooks/storybook"
"url": "https://github.com/storybooks/storybook.git"
},
"license": "MIT",
"author": "Renaud Tertrais <renaud.tertrais@gmail.com> (https://github.com/renaudtertrais)",
@ -25,11 +30,12 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@emotion/styled": "0.10.5",
"@storybook/addons": "4.0.0-alpha.21",
"@storybook/components": "4.0.0-alpha.21",
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.0-rc.1",
"@storybook/components": "4.0.0-rc.1",
"global": "^4.3.2",
"prop-types": "^15.6.2",
"upath": "^1.1.0",
"util-deprecate": "^1.0.2"
},
"peerDependencies": {

View File

@ -1,17 +1,18 @@
import addons from '@storybook/addons';
import deprecate from 'util-deprecate';
import { normalize } from 'upath';
const findTestResults = (testFiles, jestTestResults, jestTestFilesExt) =>
Object.values(testFiles).map(name => {
const fileName = `${name}${jestTestFilesExt}`;
if (jestTestResults && jestTestResults.testResults) {
return {
fileName,
name,
result: jestTestResults.testResults.find(t =>
new RegExp(`${name}${jestTestFilesExt}`).test(t.name)
),
result: jestTestResults.testResults.find(t => normalize(t.name).includes(fileName)),
};
}
return { name };
return { fileName, name };
});
const emitAddTests = ({ kind, story, testFiles, options }) => {

View File

@ -7,7 +7,7 @@ import Panel from './components/Panel';
addons.register('storybook/tests', api => {
const channel = addons.getChannel();
addons.addPanel('storybook/tests/panel', {
title: <PanelTitle channel={addons.getChannel()} api={api} />,
title: () => <PanelTitle channel={channel} api={api} />,
// eslint-disable-next-line react/prop-types
render: ({ active }) => <Panel channel={channel} api={api} active={active} />,
});

View File

@ -263,13 +263,15 @@ Allows you to get a value from a list of radio buttons from the user.
```js
import { radios } from '@storybook/addon-knobs';
const label = 'Fruits';
const options = {
Kiwi: 'kiwi',
Guava: 'guava',
Watermelon: 'watermelon',
};
};
const defaultValue = 'kiwi';
const = radios(name, options, defaultValue);
const value = radios(label, options, defaultValue);
```
### files

View File

@ -1,7 +1,18 @@
{
"name": "@storybook/addon-knobs",
"version": "4.0.0-alpha.21",
"version": "4.0.0-rc.1",
"description": "Storybook Addon Prop Editor Component",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/knobs",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git"
@ -13,10 +24,10 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@emotion/styled": "0.10.5",
"@storybook/addons": "4.0.0-alpha.21",
"@storybook/components": "4.0.0-alpha.21",
"@storybook/core-events": "4.0.0-alpha.21",
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.0-rc.1",
"@storybook/components": "4.0.0-rc.1",
"@storybook/core-events": "4.0.0-rc.1",
"copy-to-clipboard": "^3.0.8",
"escape-html": "^1.0.3",
"fast-deep-equal": "^2.0.1",
@ -24,13 +35,9 @@
"prop-types": "^15.6.2",
"qs": "^6.5.2",
"react-color": "^2.14.1",
"react-datetime": "^2.15.0",
"react-lifecycles-compat": "^3.0.4",
"util-deprecate": "^1.0.2"
},
"devDependencies": {
"vue": "^2.5.17"
},
"peerDependencies": {
"react": "*"
}

View File

@ -15,6 +15,8 @@ const getTimestamp = () => +new Date();
const DEFAULT_GROUP_ID = 'ALL';
const PanelWrapper = styled.div({
height: '100%',
overflow: 'auto',
width: '100%',
});

View File

@ -28,7 +28,9 @@ class ArrayType extends React.Component {
render() {
const { knob } = this.props;
return <Textarea id={knob.name} value={knob.value} onChange={this.handleChange} size="flex" />;
const value = knob.value.join(knob.separator);
return <Textarea id={knob.name} value={value} onChange={this.handleChange} size="flex" />;
}
}

View File

@ -28,10 +28,13 @@ class ColorType extends React.Component {
document.addEventListener('mousedown', this.handleWindowMouseDown);
}
shouldComponentUpdate(nextProps) {
shouldComponentUpdate(nextProps, nextState) {
const { knob } = this.props;
const { displayColorPicker } = this.state;
return nextProps.knob.value !== knob.value;
return (
nextProps.knob.value !== knob.value || nextState.displayColorPicker !== displayColorPicker
);
}
componentWillUnmount() {

View File

@ -0,0 +1,139 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import styled from '@emotion/styled';
import { Input } from '@storybook/components';
const FlexSpaced = styled.div({
flex: 1,
display: 'flex',
'& > *': {
marginLeft: 10,
},
'& > *:first-child': {
marginLeft: 0,
},
});
const FlexInput = styled(Input)({ flex: 1 });
const formatDate = date => {
const year = `000${date.getFullYear()}`.slice(-4);
const month = `0${date.getMonth() + 1}`.slice(-2);
const day = `0${date.getDate()}`.slice(-2);
return `${year}-${month}-${day}`;
};
const formatTime = date => {
const hours = `0${date.getHours()}`.slice(-2);
const minutes = `0${date.getMinutes()}`.slice(-2);
return `${hours}:${minutes}`;
};
class DateType extends Component {
static getDerivedStateFromProps() {
return { valid: true };
}
state = {
valid: undefined,
};
componentDidUpdate() {
const { knob } = this.props;
const { valid } = this.state;
const value = new Date(knob.value);
if (valid !== false) {
this.dateInput.value = formatDate(value);
this.timeInput.value = formatTime(value);
}
}
onDateChange = e => {
const { knob, onChange } = this.props;
const { state } = this;
let valid = false;
const [year, month, day] = e.target.value.split('-');
const result = new Date(knob.value);
if (result.getTime()) {
result.setFullYear(parseInt(year, 10));
result.setMonth(parseInt(month, 10) - 1);
result.setDate(parseInt(day, 10));
if (result.getTime()) {
valid = true;
onChange(result.getTime());
}
}
if (valid !== state.valid) {
this.setState({ valid });
}
};
onTimeChange = e => {
const { knob, onChange } = this.props;
const { state } = this;
let valid = false;
const [hours, minutes] = e.target.value.split(':');
const result = new Date(knob.value);
if (result.getTime()) {
result.setHours(parseInt(hours, 10));
result.setMinutes(parseInt(minutes, 10));
if (result.getTime()) {
onChange(result.getTime());
valid = true;
}
}
if (valid !== state.valid) {
this.setState({ valid });
}
};
render() {
const { knob } = this.props;
const { name } = knob;
const { valid } = this.state;
return name ? (
<FlexSpaced style={{ display: 'flex' }}>
<FlexInput
type="date"
max="9999-12-31" // I do this because of a rendering bug in chrome
ref={el => {
this.dateInput = el;
}}
id={`${name}date`}
onChange={this.onDateChange}
/>
<FlexInput
type="time"
id={`${name}time`}
ref={el => {
this.timeInput = el;
}}
onChange={this.onTimeChange}
/>
{!valid ? <div>invalid</div> : null}
</FlexSpaced>
) : null;
}
}
DateType.defaultProps = {
knob: {},
onChange: value => value,
};
DateType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.number,
}),
onChange: PropTypes.func,
};
DateType.serialize = value => new Date(value).getTime() || new Date().getTime();
DateType.deserialize = value => new Date(value).getTime() || new Date().getTime();
export default DateType;

View File

@ -1,50 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import styled from '@emotion/styled';
import Datetime from 'react-datetime';
import style from './styles';
const DateInput = styled(Datetime)(style);
class DateType extends React.Component {
shouldComponentUpdate(nextProps) {
const { knob } = this.props;
return nextProps.knob.value !== knob.value;
}
handleChange = date => {
const { onChange } = this.props;
const value = date.valueOf();
onChange(value);
};
render() {
const { knob } = this.props;
return (
<DateInput
value={knob.value ? new Date(knob.value) : null}
type="date"
onChange={this.handleChange}
size="flex"
/>
);
}
}
DateType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.number,
}).isRequired,
onChange: PropTypes.func.isRequired,
};
DateType.serialize = value => String(value);
DateType.deserialize = value => parseFloat(value);
export default DateType;

View File

@ -1,202 +0,0 @@
import { Input } from '@storybook/components';
export default ({ theme, size }) => ({
...Input.sizes({ size, theme }),
'&.rdt': {
position: 'relative',
},
'& > input': {
width: '100%',
height: 32,
...Input.styles({ theme }),
...Input.alignment({ theme }),
},
'& .rdtPicker': {
display: 'none',
position: 'absolute',
width: 200,
padding: 4,
marginTop: 1,
zIndex: 99999,
background: theme.barFill,
},
'&.rdtOpen .rdtPicker': {
display: 'block',
},
'&.rdt .rdtPicker': {
boxShadow: 'none',
position: 'static',
},
'& .rdtPicker .rdtTimeToggle': {
textAlign: 'center',
fontSize: 11,
},
'& .rdtPicker table': {
width: '100%',
margin: 0,
},
'& .rdtPicker td, & .rdtPicker th': {
textAlign: 'center',
height: 32,
boxSizing: 'border-box',
},
'& .rdtPicker td': {
cursor: 'pointer',
},
'& .rdtPicker td.rdtDay:hover, & .rdtPicker td.rdtHour:hover, & .rdtPicker td.rdtMinute:hover, & .rdtPicker td.rdtSecond:hover, & .rdtPicker .rdtTimeToggle:hover': {
color: theme.highlightColor,
textDecoration: 'underline',
cursor: 'pointer',
},
'& .rdtPicker td.rdtOld, & .rdtPicker td.rdtNew': {
color: '#999999',
},
'& .rdtPicker td.rdtToday': {
position: 'relative',
},
'& .rdtPicker td.rdtToday:before': {
content: '""',
display: 'inline-block',
borderLeft: '7px solid transparent',
borderBottom: `7px solid ${theme.highlightColor}`,
borderTopColor: 'rgba(0, 0, 0, 0.2)',
position: 'absolute',
bottom: 4,
right: 4,
},
'& .rdtPicker td.rdtActive, & .rdtPicker td.rdtActive:hover': {
backgroundColor: theme.highlightColor,
color: '#fff',
textShadow:
'0 -1px 0 rgba(0,0,0,0.25), 0 1px 0 rgba(0,0,0,0.25), -1px 0 0 rgba(0,0,0,0.25), 1px 0 0 rgba(0,0,0,0.25)',
},
'& .rdtPicker td.rdtActive.rdtToday:before': {
borderBottomColor: '#fff',
},
'& .rdtPicker td.rdtDisabled, & .rdtPicker td.rdtDisabled:hover': {
background: 'none',
color: '#999999',
cursor: 'not-allowed',
},
'& .rdtPicker td span.rdtOld': {
color: '#999999',
},
'& .rdtPicker td span.rdtDisabled, & .rdtPicker td span.rdtDisabled:hover': {
background: 'none',
color: '#999999',
cursor: 'not-allowed',
},
'& .rdtPicker th': {
borderBottom: `1px solid ${theme.highlightColor}`,
},
'& .rdtPicker .dow': {
width: '14.2857%',
fontSize: 11,
borderBottom: 'none',
},
'& .rdtPicker th.rdtSwitch': {
width: 100,
fontSize: 11,
},
'& .rdtPicker th.rdtNext, & .rdtPicker th.rdtPrev': {
fontSize: 11,
verticalAlign: 'middle',
},
'& .rdtPrev span, & .rdtNext span': {
display: 'block',
userSelect: 'none',
},
'& .rdtPicker th.rdtDisabled, & .rdtPicker th.rdtDisabled:hover': {
background: 'none',
color: '#999999',
cursor: 'not-allowed',
},
'& .rdtPicker thead tr:first-child th': {
cursor: 'pointer',
},
'& .rdtPicker thead tr:first-child th:hover': {
color: theme.highlightColor,
},
'& .rdtPicker tfoot': {
borderTop: '1px solid #f9f9f9',
},
'& .rdtPicker button': {
border: 'none',
background: 'none',
cursor: 'pointer',
},
'& .rdtPicker button:hover': {
color: theme.highlightColor,
},
'& .rdtPicker thead button': {
width: '100%',
height: '100%',
},
'& td.rdtMonth, & td.rdtYear': {
height: 50,
width: '25%',
cursor: 'pointer',
},
'& td.rdtMonth:hover, & td.rdtYear:hover': {
color: theme.highlightColor,
},
'& td.rdtDay': {
fontSize: 11,
},
'& .rdtCounters': {
display: 'inline-block',
},
'& .rdtCounters > div': {
float: 'left',
},
'& .rdtCounter': {
height: 100,
width: 40,
},
'& .rdtCounterSeparator': {
lineHeight: '100px',
},
'& .rdtCounter .rdtBtn': {
height: '40%',
lineHeight: '40px',
cursor: 'pointer',
display: 'block',
fontSize: 11,
userSelect: 'none',
},
'& .rdtCounter .rdtBtn:hover': {
color: theme.highlightColor,
},
'& .rdtCounter .rdtCount': {
height: '20%',
fontSize: 11,
},
'& .rdtMilli': {
verticalSlign: 'middle',
paddingLeft: 8,
width: 48,
},
'& .rdtMilli input': {
width: '100%',
fontSize: 11,
marginTop: 37,
},
});

View File

@ -36,7 +36,7 @@ SelectType.defaultProps = {
SelectType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.string,
value: PropTypes.any,
options: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
}),
onChange: PropTypes.func,

View File

@ -1,11 +1,15 @@
{
"name": "@storybook/addon-links",
"version": "4.0.0-alpha.21",
"version": "4.0.0-rc.1",
"description": "Story Links addon for storybook",
"keywords": [
"addon",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/links",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
@ -20,9 +24,9 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.0-alpha.21",
"@storybook/components": "4.0.0-alpha.21",
"@storybook/core-events": "4.0.0-alpha.21",
"@storybook/addons": "4.0.0-rc.1",
"@storybook/components": "4.0.0-rc.1",
"@storybook/core-events": "4.0.0-rc.1",
"global": "^4.3.2",
"prop-types": "^15.6.2"
},

View File

@ -1,12 +1,19 @@
{
"name": "@storybook/addon-notes",
"version": "4.0.0-alpha.21",
"version": "4.0.0-rc.1",
"description": "Write notes for your Storybook stories.",
"keywords": [
"addon",
"notes",
"storybook"
],
"homepage": "https://github.com/storybooks/storybook/tree/master/addons/notes",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git"
@ -18,9 +25,9 @@
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@emotion/styled": "0.10.5",
"@storybook/addons": "4.0.0-alpha.21",
"marked": "^0.5.0",
"@emotion/styled": "^0.10.6",
"@storybook/addons": "4.0.0-rc.1",
"marked": "^0.5.1",
"prop-types": "^15.6.2"
},
"peerDependencies": {

View File

@ -2,8 +2,7 @@ import addons, { makeDecorator } from '@storybook/addons';
import marked from 'marked';
function renderMarkdown(text, options) {
marked.setOptions({ ...marked.defaults, options });
return marked(text);
return marked(text, { ...marked.defaults, ...options });
}
export const withNotes = makeDecorator({

View File

@ -0,0 +1,89 @@
# Storybook Addon On Device Backgrounds
Storybook On Device Background Addon can be used to change background colors inside the the simulator in [Storybook](https://storybook.js.org).
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)
![Storybook Addon Backgrounds Demo](docs/demo.png)
## Installation
```sh
npm i -D @storybook/addon-ondevice-backgrounds
```
## Configuration
Then create a file called `rn-addons.js` in your storybook config.
Add following content to it:
```js
import '@storybook/addon-ondevice-backgrounds/register';
```
Then import `rn-addons.js` next to your `getStorybookUI` call.
```js
import './rn-addons';
```
## Usage
Then write your stories like this:
```js
import React from 'react';
import { storiesOf } from '@storybook/react-native';
import { withBackgrounds } from '@storybook/addon-ondevice-backgrounds';
storiesOf('Button', module)
.addDecorator(
withBackgrounds([
{ name: 'twitter', value: '#00aced', default: true },
{ name: 'facebook', value: '#3b5998' },
])
)
.add('with text', () => <Text>Click me</Text>);
```
You can add the backgrounds to all stories with `addDecorator` in `.storybook/config.js`:
```js
import { addDecorator } from '@storybook/react-native'; // <- or your storybook framework
import { withBackgrounds } from '@storybook/addon-ondevice-backgrounds';
addDecorator(
withBackgrounds([
{ name: 'twitter', value: '#00aced', default: true },
{ name: 'facebook', value: '#3b5998' },
])
);
```
If you want to override backgrounds for a single story or group of stories, pass the `backgrounds` parameter:
```js
import React from 'react';
import { storiesOf } from '@storybook/react-native';
storiesOf('Button', module)
.addParameters({
backgrounds: [
{ name: 'red', value: '#F44336' },
{ name: 'blue', value: '#2196F3', default: true },
],
})
.add('with text', () => <button>Click me</button>);
```
If you don't want to use backgrounds for a story, you can set the `backgrounds` parameter to `[]`, or use `{ disable: true }` to skip the addon:
```js
import React from 'react';
import { storiesOf } from '@storybook/react-native';
storiesOf('Button', module).add('with text', () => <button>Click me</button>, {
backgrounds: { disable: true },
});
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

View File

@ -0,0 +1,36 @@
{
"name": "@storybook/addon-ondevice-backgrounds",
"version": "4.0.0-rc.1",
"description": "A storybook addon to show different backgrounds for your preview",
"keywords": [
"addon",
"background",
"react",
"storybook"
],
"homepage": "https://storybook.js.org",
"publishConfig": {
"access": "public"
},
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git"
},
"license": "MIT",
"main": "dist/index.js",
"jsnext:main": "src/index.js",
"scripts": {
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.0-rc.1",
"prop-types": "^15.6.2"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
}

View File

@ -0,0 +1 @@
require('./dist/register');

View File

@ -0,0 +1,112 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { View, Text } from 'react-native';
import Events from './constants';
import Swatch from './Swatch';
const defaultBackground = {
name: 'default',
value: 'transparent',
};
const instructionsHtml = `
import { storiesOf } from '@storybook/react';
import { withBackgrounds } from '@storybook/addon-backgrounds';
storiesOf('First Component', module)
.addDecorator(withBackgrounds([
{ name: 'twitter', value: '#00aced' },
{ name: 'facebook', value: '#3b5998" },
]))
.add("First Button", () => <button>Click me</button>);
`.trim();
const Instructions = () => (
<View>
<Text style={{ fontSize: 16 }}>Setup Instructions</Text>
<Text>
Please add the background decorator definition to your story. The background decorate accepts
an array of items, which should include a name for your color (preferably the css class name)
and the corresponding color / image value.
</Text>
<Text>
Below is an example of how to add the background decorator to your story definition.
</Text>
<Text>{instructionsHtml}</Text>
</View>
);
export default class BackgroundPanel extends Component {
constructor(props) {
super(props);
this.state = { backgrounds: [] };
}
componentDidMount() {
const { channel } = this.props;
this.onSet = channel.on(Events.SET, data => {
const backgrounds = [...data];
this.setState({ backgrounds });
});
this.onUnset = channel.on(Events.UNSET, () => {
this.setState({ backgrounds: [] });
});
}
componentWillUnmount() {
const { channel } = this.props;
channel.removeListener(Events.SET, this.onSet);
channel.removeListener(Events.UNSET, this.onUnset);
}
setBackgroundFromSwatch = background => {
this.update(background);
};
update(background) {
const { channel } = this.props;
channel.emit(Events.UPDATE_BACKGROUND, background);
}
render() {
const { active } = this.props;
const { backgrounds = [] } = this.state;
if (!active) {
return null;
}
if (!backgrounds.length) return <Instructions />;
const hasDefault = backgrounds.filter(x => x.default).length;
if (!hasDefault) backgrounds.push(defaultBackground);
return (
<View>
{backgrounds.map(({ value, name }) => (
<View key={`${name} ${value}`}>
<Swatch value={value} name={name} setBackground={this.setBackgroundFromSwatch} />
</View>
))}
</View>
);
}
}
BackgroundPanel.propTypes = {
active: PropTypes.bool.isRequired,
api: PropTypes.shape({
getQueryParam: PropTypes.func,
setQueryParams: PropTypes.func,
}).isRequired,
channel: PropTypes.shape({
emit: PropTypes.func,
on: PropTypes.func,
removeListener: PropTypes.func,
}),
};
BackgroundPanel.defaultProps = {
channel: undefined,
};

View File

@ -0,0 +1,30 @@
import React from 'react';
import PropTypes from 'prop-types';
import { TouchableOpacity, View, Text } from 'react-native';
const Swatch = ({ name, value, setBackground }) => (
<TouchableOpacity
style={{
borderRadius: 4,
borderWidth: 1,
borderColor: 'rgba(0,0,0,0.2)',
marginTop: 10,
marginBottom: 20,
marginHorizontal: 10,
}}
onPress={() => setBackground(value)}
>
<View style={{ flex: 1, backgroundColor: value, height: 40 }} />
<View style={{ padding: 4, flexDirection: 'row', justifyContent: 'space-between' }}>
<Text>{name}:</Text>
<Text>{value}</Text>
</View>
</TouchableOpacity>
);
Swatch.propTypes = {
name: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
setBackground: PropTypes.func.isRequired,
};
export default Swatch;

View File

@ -0,0 +1,8 @@
export const ADDON_ID = 'storybook-addon-background';
export const PANEL_ID = `${ADDON_ID}/background-panel`;
export default {
SET: `${ADDON_ID}:set`,
UNSET: `${ADDON_ID}:unset`,
UPDATE_BACKGROUND: `${ADDON_ID}:update`,
};

View File

@ -0,0 +1,52 @@
import React from 'react';
import { View } from 'react-native';
import PropTypes from 'prop-types';
import Events from './constants';
export default class Container extends React.Component {
constructor(props) {
super(props);
this.state = { background: props.initialBackground || '' };
this.onBackgroundChange = this.onBackgroundChange.bind(this);
}
componentDidMount() {
const { channel } = this.props;
// Listen to the notes and render it.
channel.on(Events.UPDATE_BACKGROUND, this.onBackgroundChange);
}
// This is some cleanup tasks when the Notes panel is unmounting.
componentWillUnmount() {
const { channel } = this.props;
channel.removeListener(Events.UPDATE_BACKGROUND, this.onBackgroundChange);
}
onBackgroundChange(background) {
this.setState({ background });
}
render() {
const { background } = this.state;
const { children } = this.props;
return (
<View style={{ flex: 1, backgroundColor: background || 'transparent' }}>{children}</View>
);
}
}
Container.propTypes = {
channel: PropTypes.shape({
emit: PropTypes.func,
on: PropTypes.func,
removeListener: PropTypes.func,
}),
initialBackground: PropTypes.string,
children: PropTypes.node.isRequired,
};
Container.defaultProps = {
channel: undefined,
initialBackground: '',
};

View File

@ -0,0 +1,34 @@
import React from 'react';
import addons, { makeDecorator } from '@storybook/addons';
import Events from './constants';
import Container from './container';
export const withBackgrounds = makeDecorator({
name: 'withBackgrounds',
parameterName: 'backgrounds',
skipIfNoParametersOrOptions: true,
allowDeprecatedUsage: true,
wrapper: (getStory, context, { options, parameters }) => {
const data = parameters || options || [];
const backgrounds = Array.isArray(data) ? data : Object.values(data);
let background = 'transparent';
if (backgrounds.length !== 0) {
addons.getChannel().emit(Events.SET, backgrounds);
const defaultOrFirst = backgrounds.find(x => x.default) || backgrounds[0];
if (defaultOrFirst) {
background = defaultOrFirst.value;
}
}
return (
<Container initialBackground={background} channel={addons.getChannel()}>
{getStory(context)}
</Container>
);
},
});

View File

@ -0,0 +1,14 @@
import React from 'react';
import addons from '@storybook/addons';
import { ADDON_ID, PANEL_ID } from './constants';
import BackgroundPanel from './BackgroundPanel';
addons.register(ADDON_ID, api => {
const channel = addons.getChannel();
addons.addPanel(PANEL_ID, {
title: 'Backgrounds',
// eslint-disable-next-line react/prop-types
render: ({ active }) => <BackgroundPanel channel={channel} api={api} active={active} />,
});
});

View File

@ -0,0 +1,38 @@
# Storybook Addon On Device Knobs
Storybook Addon On Device Knobs allow you to edit React props dynamically using the Storybook UI.
You can also use Knobs as a dynamic variable inside stories in [Storybook](https://storybook.js.org).
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)
This is how Knobs look like:
[![Storybook Knobs Demo](docs/storybook-knobs-example.png)](https://storybooks-official.netlify.com/?knob-Dollars=12.5&knob-Name=Storyteller&knob-Years%20in%20NY=9&knob-background=%23ffff00&knob-Age=70&knob-Items%5B0%5D=Laptop&knob-Items%5B1%5D=Book&knob-Items%5B2%5D=Whiskey&knob-Other%20Fruit=lime&knob-Birthday=1484870400000&knob-Nice=true&knob-Styles=%7B%22border%22%3A%223px%20solid%20%23ff00ff%22%2C%22padding%22%3A%2210px%22%7D&knob-Fruit=apple&selectedKind=Addons%7CKnobs.withKnobs&selectedStory=tweaks%20static%20values&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybooks%2Fstorybook-addon-knobs)
**This addon is a wrapper for addon [@storybook/addon-knobs](https://github.com/storybooks/storybook/blob/master/addons/knobs).
Refer to its documentation to understand how to use knobs**
## Getting Started
First of all, you need to install knobs into your project.
```sh
npm install @storybook/addon-ondevice-knobs
```
Then create a file called `rn-addons.js` in your storybook config.
```js
import '@storybook/addon-ondevice-knobs/register';
```
Then import `rn-addons.js` next to your `getStorybookUI` call.
```js
import './rn-addons';
```
Now, write your stories with knobs.
**Refer to [@storybook/addon-knobs](https://github.com/storybooks/storybook/blob/master/addons/knobs) to learn how to write stories.**

View File

@ -0,0 +1,39 @@
{
"name": "@storybook/addon-ondevice-knobs",
"version": "4.0.0-rc.1",
"description": "Display storybook story knobs on your deviced.",
"keywords": [
"addon",
"knobs",
"ondevice",
"react-native",
"storybook"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git"
},
"license": "MIT",
"main": "dist/index.js",
"jsnext:main": "src/index.js",
"scripts": {
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.0-rc.1",
"deep-equal": "^1.0.1",
"prop-types": "^15.6.2",
"react-native-color-picker": "^0.4.0",
"react-native-modal-datetime-picker": "^5.1.0",
"react-native-modal-selector": "^0.0.29",
"react-native-switch": "^1.5.0"
},
"peerDependencies": {
"@storybook/addon-knobs": "4.0.0-alpha.24",
"react": "*",
"react-native": "*"
}
}

View File

@ -0,0 +1 @@
require('./dist/index').register();

View File

@ -0,0 +1,72 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { ScrollView, Text, TouchableOpacity } from 'react-native';
class GroupTabs extends Component {
renderTab(name, group) {
let { title } = group;
if (typeof title === 'function') {
title = title();
}
const { onGroupSelect, selectedGroup } = this.props;
return (
<TouchableOpacity
style={{
marginRight: 15,
paddingBottom: 10,
}}
key={name}
onPress={() => onGroupSelect(name)}
>
<Text
style={{
color: selectedGroup === name ? 'black' : '#ccc',
fontSize: 17,
}}
>
{title}
</Text>
</TouchableOpacity>
);
}
render() {
const { groups } = this.props;
const entries = groups ? Object.entries(groups) : null;
return entries && entries.length ? (
<ScrollView
horizontal
style={{
marginHorizontal: 10,
flexDirection: 'row',
marginBottom: 10,
borderBottomWidth: 1,
borderBottomColor: '#ccc',
}}
>
{entries.map(([key, value]) => this.renderTab(key, value))}
</ScrollView>
) : (
<Text>no groups available</Text>
);
}
}
GroupTabs.defaultProps = {
groups: {},
onGroupSelect: () => {},
selectedGroup: null,
};
GroupTabs.propTypes = {
// eslint-disable-next-line react/forbid-prop-types
groups: PropTypes.object,
onGroupSelect: PropTypes.func,
selectedGroup: PropTypes.string,
};
export default GroupTabs;

View File

@ -0,0 +1,39 @@
import PropTypes from 'prop-types';
import { View, Text } from 'react-native';
import React from 'react';
import TypeMap from './types';
const InvalidType = () => <Text style={{ margin: 10 }}>Invalid Type</Text>;
const PropField = ({ onChange, onPress, knob }) => {
const InputType = TypeMap[knob.type] || InvalidType;
return (
<View>
{!knob.hideLabel ? (
<Text
style={{
marginLeft: 10,
fontSize: 14,
color: 'rgb(68, 68, 68)',
fontWeight: 'bold',
}}
>
{`${knob.name}`}
</Text>
) : null}
<InputType knob={knob} onChange={onChange} onPress={onPress} />
</View>
);
};
PropField.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.any,
}).isRequired,
onChange: PropTypes.func.isRequired,
onPress: PropTypes.func.isRequired,
};
export default PropField;

View File

@ -0,0 +1,56 @@
/* eslint no-underscore-dangle: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import { View } from 'react-native';
import PropField from './PropField';
export default class propForm extends React.Component {
makeChangeHandler(name, type) {
return value => {
const { onFieldChange } = this.props;
const change = { name, type, value };
onFieldChange(change);
};
}
render() {
const { knobs, onFieldClick } = this.props;
return (
<View>
{knobs.map(knob => {
const changeHandler = this.makeChangeHandler(knob.name, knob.type);
return (
<PropField
key={knob.name}
name={knob.name}
type={knob.type}
value={knob.value}
knob={knob}
onChange={changeHandler}
onPress={onFieldClick}
/>
);
})}
</View>
);
}
}
propForm.displayName = 'propForm';
propForm.defaultProps = {
knobs: [],
};
propForm.propTypes = {
knobs: PropTypes.arrayOf(
PropTypes.shape({
name: PropTypes.string,
value: PropTypes.any,
})
),
onFieldChange: PropTypes.func.isRequired,
onFieldClick: PropTypes.func.isRequired,
};

View File

@ -0,0 +1,14 @@
import React from 'react';
import addons from '@storybook/addons';
import Panel from './panel';
export function register() {
addons.register('RNKNOBS', () => {
const channel = addons.getChannel();
addons.addPanel('RNKNOBS', {
title: 'Knobs',
// eslint-disable-next-line react/prop-types
render: ({ active }) => <Panel channel={channel} active={active} />,
});
});
}

View File

@ -0,0 +1,170 @@
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import PropTypes from 'prop-types';
import GroupTabs from './GroupTabs';
import PropForm from './PropForm';
const getTimestamp = () => +new Date();
const DEFAULT_GROUP_ID = 'ALL';
export default class Panel extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
this.setKnobs = this.setKnobs.bind(this);
this.reset = this.reset.bind(this);
this.setOptions = this.setOptions.bind(this);
this.onGroupSelect = this.onGroupSelect.bind(this);
this.state = { knobs: {}, groupId: DEFAULT_GROUP_ID };
this.options = {};
this.lastEdit = getTimestamp();
this.loadedFromUrl = false;
}
componentDidMount() {
const { channel } = this.props;
channel.on('addon:knobs:setKnobs', this.setKnobs);
channel.on('addon:knobs:setOptions', this.setOptions);
channel.on('selectStory', this.reset);
channel.emit('forceReRender');
}
componentWillUnmount() {
const { channel } = this.props;
channel.removeListener('addon:knobs:setKnobs', this.setKnobs);
channel.removeListener('selectStory', this.reset);
}
onGroupSelect(name) {
this.setState({ groupId: name });
}
setOptions(options = { timestamps: false }) {
this.options = options;
}
setKnobs({ knobs, timestamp }) {
if (!this.options.timestamps || !timestamp || this.lastEdit <= timestamp) {
this.setState({ knobs });
}
}
reset = () => {
const { channel } = this.props;
this.setState({ knobs: {} });
channel.emit('addon:knobs:reset');
};
emitChange(changedKnob) {
const { channel } = this.props;
channel.emit('addon:knobs:knobChange', changedKnob);
}
handleChange(changedKnob) {
this.lastEdit = getTimestamp();
const { knobs } = this.state;
const { name } = changedKnob;
const newKnobs = { ...knobs };
newKnobs[name] = {
...newKnobs[name],
...changedKnob,
};
this.setState({ knobs: newKnobs });
this.setState({ knobs: newKnobs }, this.emitChange(changedKnob));
}
handleClick(knob) {
const { channel } = this.props;
channel.emit('addon:knobs:knobClick', knob);
}
render() {
const { active } = this.props;
if (!active) {
return null;
}
const { knobs, groupId } = this.state;
const groups = {};
const groupIds = [];
let knobsArray = Object.keys(knobs);
knobsArray.filter(key => knobs[key].groupId).forEach(key => {
const knobKeyGroupId = knobs[key].groupId;
groupIds.push(knobKeyGroupId);
groups[knobKeyGroupId] = {
render: () => <Text id={knobKeyGroupId}>{knobKeyGroupId}</Text>,
title: knobKeyGroupId,
};
});
if (groupIds.length > 0) {
groups[DEFAULT_GROUP_ID] = {
render: () => <Text id={DEFAULT_GROUP_ID}>{DEFAULT_GROUP_ID}</Text>,
title: DEFAULT_GROUP_ID,
};
if (groupId !== DEFAULT_GROUP_ID) {
knobsArray = knobsArray.filter(key => knobs[key].groupId === groupId);
}
}
knobsArray = knobsArray.map(key => knobs[key]);
if (knobsArray.length === 0) {
return <Text>NO KNOBS</Text>;
}
return (
<View style={{ flex: 1 }}>
{groupIds.length > 0 && (
<GroupTabs groups={groups} onGroupSelect={this.onGroupSelect} selectedGroup={groupId} />
)}
<View>
<PropForm
knobs={knobsArray}
onFieldChange={this.handleChange}
onFieldClick={this.handleClick}
/>
</View>
<TouchableOpacity
style={{
borderRadius: 2,
borderWidth: 1,
borderColor: '#f7f4f4',
padding: 4,
margin: 10,
justifyContent: 'center',
alignItems: 'center',
}}
onPress={this.reset}
>
<Text>RESET</Text>
</TouchableOpacity>
</View>
);
}
}
Panel.propTypes = {
active: PropTypes.bool.isRequired,
channel: PropTypes.shape({
emit: PropTypes.func,
on: PropTypes.func,
removeListener: PropTypes.func,
}).isRequired,
onReset: PropTypes.object, // eslint-disable-line
};

View File

@ -0,0 +1,53 @@
import PropTypes from 'prop-types';
import React from 'react';
import { TextInput } from 'react-native';
function formatArray(value, separator) {
if (value === '') {
return [];
}
return value.split(separator);
}
const ArrayType = ({ knob, onChange }) => (
<TextInput
id={knob.name}
underlineColorAndroid="transparent"
style={{
borderWidth: 1,
borderColor: '#f7f4f4',
borderRadius: 2,
fontSize: 13,
padding: 5,
margin: 10,
color: '#555',
}}
value={knob.value.join(knob.separator)}
onChangeText={e => onChange(formatArray(e, knob.separator))}
/>
);
ArrayType.defaultProps = {
knob: {},
onChange: value => value,
};
ArrayType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.array,
}),
onChange: PropTypes.func,
};
ArrayType.serialize = value => value;
ArrayType.deserialize = value => {
if (Array.isArray(value)) return value;
return Object.keys(value)
.sort()
.reduce((array, key) => [...array, value[key]], []);
};
export default ArrayType;

View File

@ -0,0 +1,39 @@
import PropTypes from 'prop-types';
import { View } from 'react-native';
import { Switch } from 'react-native-switch';
import React from 'react';
class BooleanType extends React.Component {
onValueChange = () => {
const { onChange, knob } = this.props;
onChange(!knob.value);
};
render() {
const { knob } = this.props;
return (
<View style={{ margin: 10 }}>
<Switch id={knob.name} onValueChange={this.onValueChange} value={knob.value} />
</View>
);
}
}
BooleanType.defaultProps = {
knob: {},
onChange: value => value,
};
BooleanType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.bool,
}),
onChange: PropTypes.func,
};
BooleanType.serialize = value => (value ? String(value) : null);
BooleanType.deserialize = value => value === 'true';
export default BooleanType;

View File

@ -0,0 +1,25 @@
import PropTypes from 'prop-types';
import React from 'react';
import { TouchableOpacity, Text } from 'react-native';
const ButtonType = ({ knob, onPress }) => (
<TouchableOpacity style={{ margin: 10 }} onPress={() => onPress(knob)}>
<Text style={{ fontSize: 17, color: '#007aff' }}>{knob.name}</Text>
</TouchableOpacity>
);
ButtonType.defaultProps = {
knob: {},
};
ButtonType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
}),
onPress: PropTypes.func.isRequired,
};
ButtonType.serialize = value => value;
ButtonType.deserialize = value => value;
export default ButtonType;

View File

@ -0,0 +1,101 @@
import PropTypes from 'prop-types';
import React from 'react';
import { Text, Modal, View, TouchableOpacity, TouchableWithoutFeedback } from 'react-native';
import { ColorPicker, fromHsv } from 'react-native-color-picker';
class ColorType extends React.Component {
constructor(props) {
super(props);
this.state = {
displayColorPicker: false,
};
}
openColorPicker = () => {
this.setState({
displayColorPicker: true,
});
};
closeColorPicker = () => {
this.setState({
displayColorPicker: false,
});
};
onChangeColor = color => {
const { onChange } = this.props;
onChange(fromHsv(color));
};
render() {
const { knob } = this.props;
const { displayColorPicker } = this.state;
const colorStyle = {
borderColor: 'rgb(247, 244, 244)',
width: 30,
height: 20,
borderRadius: 2,
margin: 10,
backgroundColor: knob.value,
};
return (
<View>
<TouchableOpacity style={colorStyle} onPress={this.openColorPicker} />
<Modal
supportedOrientations={['portrait', 'landscape']}
transparent
visible={displayColorPicker}
onRequestClose={this.closeColorPicker}
>
<TouchableWithoutFeedback onPress={this.closeColorPicker}>
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<TouchableWithoutFeedback>
<View
style={{
backgroundColor: 'white',
borderWidth: 1,
borderColor: 'rgb(247, 244, 244)',
width: 250,
height: 250,
padding: 10,
}}
>
<TouchableOpacity
onPress={this.closeColorPicker}
style={{ alignSelf: 'flex-end', padding: 5 }}
>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>X</Text>
</TouchableOpacity>
<ColorPicker
onColorSelected={this.onChangeColor}
defaultColor={knob.value}
style={{ flex: 1 }}
/>
</View>
</TouchableWithoutFeedback>
</View>
</TouchableWithoutFeedback>
</Modal>
</View>
);
}
}
ColorType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.string,
}),
onChange: PropTypes.func,
};
ColorType.defaultProps = {
knob: {},
onChange: value => value,
};
ColorType.serialize = value => value;
ColorType.deserialize = value => value;
export default ColorType;

View File

@ -0,0 +1,103 @@
import PropTypes from 'prop-types';
import React, { PureComponent } from 'react';
import { TouchableOpacity, Text, View } from 'react-native';
import DateTimePicker from 'react-native-modal-datetime-picker';
// TODO seconds support
class DateType extends PureComponent {
constructor() {
super();
this.state = {
isDateVisible: false,
isTimeVisible: false,
};
}
showDatePicker = () => {
this.setState({ isDateVisible: true });
};
showTimePicker = () => {
this.setState({ isTimeVisible: true });
};
hidePicker = () => {
this.setState({ isDateVisible: false, isTimeVisible: false });
};
onDatePicked = date => {
const value = date.valueOf();
const { onChange } = this.props;
onChange(value);
this.hidePicker();
};
render() {
const { knob } = this.props;
const { isTimeVisible, isDateVisible } = this.state;
const d = new Date(knob.value);
// https://stackoverflow.com/a/30272803
const dateString = [
`0${d.getDate()}`.slice(-2),
`0${d.getMonth() + 1}`.slice(-2),
d.getFullYear(),
].join('-');
const timeString = `${`0${d.getHours()}`.slice(-2)}:${`0${d.getMinutes()}`.slice(-2)}`;
return (
<View style={{ margin: 10 }}>
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity
style={{
borderWidth: 1,
borderColor: '#f7f4f4',
borderRadius: 2,
padding: 5,
}}
onPress={this.showDatePicker}
>
<Text style={{ fontSize: 13, color: '#555' }}>{dateString}</Text>
</TouchableOpacity>
<TouchableOpacity
style={{
borderWidth: 1,
borderColor: '#f7f4f4',
borderRadius: 2,
padding: 5,
marginLeft: 5,
}}
onPress={this.showTimePicker}
>
<Text style={{ fontSize: 13, color: '#555' }}>{timeString}</Text>
</TouchableOpacity>
</View>
<DateTimePicker
date={d}
isVisible={isTimeVisible || isDateVisible}
mode={isTimeVisible ? 'time' : 'date'}
onConfirm={this.onDatePicked}
onCancel={this.hidePicker}
/>
</View>
);
}
}
DateType.defaultProps = {
knob: {},
onChange: value => value,
};
DateType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.number,
}),
onChange: PropTypes.func,
};
DateType.serialize = value => String(value);
DateType.deserialize = value => parseFloat(value);
export default DateType;

View File

@ -0,0 +1,72 @@
import PropTypes from 'prop-types';
import React from 'react';
import { TextInput, View, Slider } from 'react-native';
class NumberType extends React.Component {
constructor(props) {
super(props);
this.renderNormal = this.renderNormal.bind(this);
this.renderRange = this.renderRange.bind(this);
}
renderNormal() {
const { knob, onChange } = this.props;
return (
<TextInput
style={{
borderWidth: 1,
borderColor: '#f7f4f4',
borderRadius: 2,
fontSize: 13,
padding: 5,
color: '#555',
}}
underlineColorAndroid="transparent"
value={knob.value.toString()}
keyboardType="numeric"
onChangeText={val => onChange(parseFloat(val))}
/>
);
}
renderRange() {
const { knob, onChange } = this.props;
return (
<Slider
value={knob.value}
minimumValue={knob.min}
maximumValue={knob.max}
step={knob.step}
onSlidingComplete={val => onChange(parseFloat(val))}
/>
);
}
render() {
const { knob } = this.props;
return (
<View style={{ margin: 10 }}>{knob.range ? this.renderRange() : this.renderNormal()}</View>
);
}
}
NumberType.defaultProps = {
knob: {},
onChange: value => value,
};
NumberType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.number,
}),
onChange: PropTypes.func,
};
NumberType.serialize = value => String(value);
NumberType.deserialize = value => parseFloat(value);
export default NumberType;

View File

@ -0,0 +1,95 @@
import PropTypes from 'prop-types';
import React from 'react';
import { TextInput } from 'react-native';
import deepEqual from 'deep-equal';
const styles = {
borderWidth: 1,
borderColor: '#f7f4f4',
borderRadius: 2,
fontSize: 13,
padding: 5,
margin: 10,
color: '#555',
};
class ObjectType extends React.Component {
constructor(...args) {
super(...args);
this.state = {};
}
getJSONString() {
const { json, jsonString } = this.state;
const { knob } = this.props;
// If there is an error in the JSON, we need to give that errored JSON.
if (this.failed) return jsonString;
// If the editor value and the knob value is the same, we need to return the
// editor value as it allow user to add new fields to the JSON.
if (deepEqual(json, knob.value)) return jsonString;
// If the knob's value is different from the editor, it seems like
// there's a outside change and we need to get that.
return JSON.stringify(knob.value, null, 2);
}
handleChange = value => {
const { onChange } = this.props;
const newState = {
jsonString: value,
};
try {
newState.json = JSON.parse(value.trim());
onChange(newState.json);
this.failed = false;
} catch (err) {
this.failed = true;
}
this.setState(newState);
};
render() {
const { knob } = this.props;
const jsonString = this.getJSONString();
const extraStyle = {};
if (this.failed) {
extraStyle.borderWidth = 1;
extraStyle.borderColor = '#fadddd';
extraStyle.backgroundColor = '#fff5f5';
}
return (
<TextInput
id={knob.name}
style={{ ...styles, ...extraStyle }}
value={jsonString}
onChangeText={this.handleChange}
multiline
underlineColorAndroid="transparent"
/>
);
}
}
ObjectType.defaultProps = {
knob: {},
onChange: value => value,
};
ObjectType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
}),
onChange: PropTypes.func,
};
ObjectType.serialize = object => JSON.stringify(object);
ObjectType.deserialize = value => (value ? JSON.parse(value) : {});
export default ObjectType;

View File

@ -0,0 +1,69 @@
/* eslint no-underscore-dangle: 0 */
import PropTypes from 'prop-types';
import { View, TextInput } from 'react-native';
import React from 'react';
import ModalPicker from 'react-native-modal-selector';
class SelectType extends React.Component {
getOptions = ({ options }) => {
if (Array.isArray(options)) {
return options.map(val => ({ key: val, label: val }));
}
return Object.keys(options).map(key => ({ label: key, key: options[key] }));
};
render() {
const { knob, onChange } = this.props;
const options = this.getOptions(knob);
const selected = options.filter(({ key }) => knob.value === key)[0].label;
return (
<View>
<ModalPicker
data={options}
initValue={knob.value}
onChange={option => onChange(option.key)}
animationType="none"
>
<TextInput
style={{
borderWidth: 1,
borderColor: '#f7f4f4',
borderRadius: 2,
padding: 5,
color: '#555',
margin: 10,
}}
editable={false}
value={selected}
underlineColorAndroid="transparent"
/>
</ModalPicker>
</View>
);
}
}
SelectType.defaultProps = {
knob: {},
onChange: value => value,
};
SelectType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.string,
options: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
selectV2: PropTypes.bool,
}),
onChange: PropTypes.func,
};
SelectType.serialize = value => value;
SelectType.deserialize = value => value;
export default SelectType;

View File

@ -0,0 +1,39 @@
import PropTypes from 'prop-types';
import React from 'react';
import { TextInput } from 'react-native';
const TextType = ({ knob, onChange }) => (
<TextInput
style={{
borderWidth: 1,
borderColor: '#f7f4f4',
borderRadius: 2,
fontSize: 13,
padding: 5,
margin: 10,
color: '#555',
}}
id={knob.name}
value={knob.value}
onChangeText={onChange}
underlineColorAndroid="transparent"
/>
);
TextType.defaultProps = {
knob: {},
onChange: value => value,
};
TextType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.string,
}),
onChange: PropTypes.func,
};
TextType.serialize = value => value;
TextType.deserialize = value => value;
export default TextType;

View File

@ -0,0 +1,21 @@
import TextType from './Text';
import NumberType from './Number';
import ColorType from './Color';
import BooleanType from './Boolean';
import ObjectType from './Object';
import SelectType from './Select';
import ArrayType from './Array';
import DateType from './Date';
import ButtonType from './Button';
export default {
text: TextType,
number: NumberType,
color: ColorType,
boolean: BooleanType,
object: ObjectType,
select: SelectType,
array: ArrayType,
date: DateType,
button: ButtonType,
};

View File

@ -0,0 +1,48 @@
# Storybook Addon On Device Notes
Storybook Addon On Device Notes allows you to write notes (text or markdown) for your stories in [Storybook](https://storybook.js.org).
[Framework Support](https://github.com/storybooks/storybook/blob/master/ADDONS_SUPPORT.md)
![Storybook Addon Notes Demo](docs/demo.png)
### Getting Started
**NOTE: Documentation on master branch is for alpha version, stable release is on [release/3.4](https://github.com/storybooks/storybook/tree/release/3.4/addons/)**
```sh
yarn add -D @storybook/addon-ondevice-notes
```
Then create a file called `rn-addons.js` in your storybook config.
Add following content to it:
```js
import '@storybook/addon-ondevice-notes/register';
```
Then import `rn-addons.js` next to your `getStorybookUI` call.
```js
import './rn-addons';
```
Then add the `withNotes` decorator to all stories in your `config.js`:
```js
// Import from @storybook/X where X is your framework
import { addDecorator } from '@storybook/react-native';
import { withNotes } from '@storybook/addon-ondevice-notes';
addDecorator(withNotes);
```
You can use the `notes` parameter to add a note to each story:
```js
import { storiesOf } from '@storybook/react-native';
import Component from './Component';
storiesOf('Component', module)
.add('with some emoji', () => <Component />, { notes: 'A very simple component' });
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

View File

@ -0,0 +1,32 @@
{
"name": "@storybook/addon-ondevice-notes",
"version": "4.0.0-rc.1",
"description": "Write notes for your Storybook stories.",
"keywords": [
"addon",
"notes",
"storybook"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git"
},
"license": "MIT",
"main": "dist/index.js",
"jsnext:main": "src/index.js",
"scripts": {
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "4.0.0-rc.1",
"prop-types": "^15.6.2",
"react-native-simple-markdown": "^1.1.0"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
}

View File

@ -0,0 +1 @@
require('./dist/register.js');

View File

@ -0,0 +1,42 @@
import addons from '@storybook/addons';
import { withNotes } from '..';
addons.getChannel = jest.fn();
describe('Storybook Addon Notes', () => {
it('should inject text from `notes` parameter', () => {
const channel = { emit: jest.fn() };
addons.getChannel.mockReturnValue(channel);
const getStory = jest.fn();
const context = { parameters: { notes: 'hello' } };
withNotes(getStory, context);
expect(channel.emit).toHaveBeenCalledWith('storybook/notes/add_notes', 'hello');
expect(getStory).toHaveBeenCalledWith(context);
});
it('should inject text even if no `notes` parameter is set to reset the addon', () => {
const channel = { emit: jest.fn() };
addons.getChannel.mockReturnValue(channel);
const getStory = jest.fn();
const context = {};
withNotes(getStory, context);
expect(channel.emit).toHaveBeenCalled();
expect(getStory).toHaveBeenCalledWith(context);
});
it('should inject markdown from `notes.markdown` parameter', () => {
const channel = { emit: jest.fn() };
addons.getChannel.mockReturnValue(channel);
const getStory = jest.fn();
const context = { parameters: { notes: { markdown: '# hello' } } };
withNotes(getStory, context);
expect(channel.emit).toHaveBeenCalledWith('storybook/notes/add_notes', '# hello');
expect(getStory).toHaveBeenCalledWith(context);
});
});

View File

@ -0,0 +1,34 @@
import addons, { makeDecorator } from '@storybook/addons';
export const withNotes = makeDecorator({
name: 'withNotes',
parameterName: 'notes',
wrapper: (getStory, context, { options, parameters }) => {
const channel = addons.getChannel();
const storyOptions = parameters || options;
if (!storyOptions) {
channel.emit('storybook/notes/add_notes', '');
return getStory(context);
}
const { text, markdown } =
typeof storyOptions === 'string' ? { text: storyOptions } : storyOptions;
if (!text && !markdown) {
throw new Error('You must set of one of `text` or `markdown` on the `notes` parameter');
}
channel.emit('storybook/notes/add_notes', text || markdown);
return getStory(context);
},
});
export const withMarkdownNotes = (text, options) =>
withNotes({
markdown: text,
markdownOptions: options,
});

Some files were not shown because too many files have changed in this diff Show More