λλ μ΄μ λ§ μ€ν 리λΆμ μ¬μ©νκΈ° μμνκ³ μ§κΈκΉμ§ κ·Έκ²μ μ’μν©λλ€. λ΄κ° κ³ μ¬νλ ν κ°μ§λ λΆλͺ¨μ μνκ° ν¬ν¨λμ΄μΌ νλ μμν "μν λΉμ μ₯" κ΅¬μ± μμλ₯Ό μ²λ¦¬νλ λ°©λ²μ
λλ€. μλ₯Ό λ€μ΄ checked
μνμ μ¬μ©νλ νμΈλμ΄ μμ΅λλ€. 체ν¬λ°μ€λ₯Ό ν΄λ¦νλ©΄ μνκ° μ νλμ§ μκ³ onChange
κ° λ°μνκ³ μ
λ°μ΄νΈλ checked
μνμ λ€μ λ°μ λκΉμ§ κΈ°λ€λ¦½λλ€. μ΄λ¬ν μ’
λ₯μ κ΅¬μ± μμλ₯Ό μ²λ¦¬νκΈ° μν λͺ¨λ² μ¬λ‘μ λν λ¬Έμλ μλ κ² κ°μΌλ©° https://github.com/storybooks/storybook/issues/197 κ³Ό κ°μ λ¬Έμ μ μ μμ λνΌ κ΅¬μ± μμλ₯Ό μμ±νκ±°λ λ€λ₯Έ μΆκ° κΈ°λ₯μ μΆκ°νμμμ€. κ°λ₯νλ©΄ κ΅¬μ± μμ λνΌλ₯Ό λ§λ€μ§ μλ κ²μ΄ μ’μ΅λλ€. λ΄ μ΄μΌκΈ°λ₯Ό κ°λ₯ν ν λ¨μνκ² μ μ§νκ³ μΆκΈ° λλ¬Έμ
λλ€.
μ΄ λ¬Έμ λ₯Ό μ²λ¦¬ν΄μΌ νλ ν κ°μ§ μμ΄λμ΄λ actions
μ λμ¨μ knobs
μ μ°κ²°νμ¬ λ
ΈλΈλ₯Ό μμ
μ ν΅ν΄ νλ‘κ·Έλλ° λ°©μμΌλ‘ ν κΈν μ μλλ‘ νλ κ²μ
λλ€. λ΄κ° λ§νλ―μ΄ λλ λνμ±
μμ μμ£Ό μλ‘μ΄ κ²μ΄λ―λ‘ μ΄κ²μ΄ μ€ν κ°λ₯νμ§ μ¬λΆλ λͺ¨λ₯΄μ§λ§ μ μ΄λ μ μμ μ κΈ°νκ³ μΆμμ΅λλ€.
μ΄κ²μ μ€ν 리λ₯Ό ꡬννλ μ μκ² μμ΄ κ±Έλ¦Όλμ΄λ©° λ€λ₯Έ μ¬λλ€μκ²λ λ§μ°¬κ°μ§μΌ κ±°λΌκ³ μκ°ν©λλ€. λνΌ κ΅¬μ± μμλ₯Ό λ§λλ κ²μ΄ μ€μ λ‘ κ°μ₯ μ’μ λ°©λ²μ΄λΌλ©΄ μ΄λ₯Ό λͺ νν νκΈ° μν΄ λ¬Έμλ₯Ό μΆκ°νκ³ μ΄λ₯Ό μννλ λ°©λ²μ 무μμ λκΉ?
μ΄ #3701 PRμ μ μ¬ν μμ΄λμ΄κ° λμ λμ΄ λ Όλμ΄ λμμ΅λλ€(ν΅ν©λμ§ μμ).
μ΄μ λν ν λ‘ μ λ€μ μ΄κ³ API μ μμ λ€μ μ μμ΅λλ€ =).
μ κ°μ¬ν©λλ€, κ·Έ PRμ λ³Έ μ μ΄ μμ΅λλ€. @aherriot μ κ°μ¬λ립λλ€. μ ν¬λ κ°μ μκ°μ νκ³ μλ κ² κ°μ΅λλ€.
APIμ λ°μ΄λ€κΈ° μ μ κΈ°λ³Έ κ°λ μ λ Όμνκ³ λμν΄μΌ ν κ² κ°μ΅λλ€. PRμ μ견 μ€ νλλ @Hypnosphiμ λ€μκ³Ό
λλ κ·Έκ²μ΄ μ§μ€μ μ¬λ¬ μμ€(κ΅¬μ± μμ μ½λ°± λ° UI μμ‘μ΄)λ₯Ό λμ νλ€λ μ¬μ€μ μ’μνμ§ μμ΅λλ€.
μ μκ°μλ λ€μν μ 보 μμ€λ₯Ό λμ
νλ κ²μ΄ μλλΌ κ΅¬μ± μμ μν(λ
ΈλΈ)μ λν΄ _λ¨μΌ_ μμ€λ₯Ό μ μ§νλλ‘ νμ©νλ κ² κ°μ΅λλ€. λ΄κ° μ μν λ€λ₯Έ λͺ¨λ μ κ·Ό λ°©μ(λνΌ κ΅¬μ± μμ, μν μΆκ° κΈ°λ₯, μ¬κ΅¬μ±)μ μ¬μ€ λ λ€λ₯Έ μμ€λ₯Ό μκ°ν©λλ€. λ΄ νμΈλ μμμλ checked
λν μμ‘μ΄λ₯Ό κ°μ§ μ μμΌλ©° λνΌ κ΅¬μ± μμκ° checked
μνμ μ 곡ν μλ μμ΅λλ€. λλ λ
ΈλΈ μ μ΄νμ κ΅¬μ± μμμ λΆλͺ¨λ‘ λ΄
λλ€. λ¨, νμ¬ κ΅¬μ± μμμμ μ½λ°±μ κ°μ Έμ¬ μ μμ΅λλ€. μ΄λ μΌμ’
μ μΌλ°©μ μ΄κ³ λ°μ μ±μ΄ μΌλ°μ μΌλ‘ λΉλλλ λ°©μμ΄ μλλλ€.
λ
ΈλΈλ₯Ό νλ‘κ·Έλλ° λ°©μμΌλ‘ μ μ΄ν μ μλλ‘ ν¨μΌλ‘μ¨ μ€ν 리λ₯Ό μμ° μ€μΈ κ΅¬μ± μμλ‘λ§ λΆλ¦¬ν μ μμΌλ©°, νμΈλκ³Ό κ°μ κ°λ¨ν νλ μ ν
μ΄μ
κ΅¬μ± μμμ κ²½μ°μ κ°μ΄ μ€μ μν κ΄λ¦¬ λ©μ»€λμ¦μ λΆν¬λͺ
νκ² λ¨κΈΈ μ μμ΅λλ€. 체ν¬λ°μ€ μ체λ propsλ₯Ό κ°μ Έμ€λ λ°©λ²μ μ κ²½ μ°μ§ μκ³ , reduxμ μ°κ²°λ μ μκ³ , λΆλͺ¨κ° setState
λ₯Ό μ¬μ©ν μλ μκ³ , recomposeμμ withState
λ₯Ό μ¬μ©ν μλ μκ³ , propsκ° λ€μμ μν΄ μ μ΄λ μλ μμ΅λλ€. λνμ±
μμ‘μ΄.
μ΄μ¨λ λ΄κ° λ§νλ―μ΄ λλ μ΄κ²μ λ§€μ° μ΅μνλ―λ‘ μ§κ΄μ μΈ μκ° λ§ κ³΅μ ν©λλ€. λ΄κ° μ€νλ² μ΄μ€μ΄κ³ μ΄λ¬ν μ’ λ₯μ μμν μν λΉμ μ₯ κ΅¬μ± μμλ₯Ό μ²λ¦¬νλ λ° μΌλ°μ μΌλ‘ μΈμ λλ "λͺ¨λ² μ¬λ‘"κ° μλ κ²½μ° λκ΅°κ° λ΄κ° λ°λ₯Ό μ μλ μ’μ μλ₯Ό μλ €μ€ μ μμ΅λκΉ?
μλ νμΈμ :)
μΆκ°νκ³ μΆμ΅λλ€. λ΄ κ΅¬μ± μμκ° μνμμ λͺ¨λ°μΌ λ μ΄μμμ νμν΄μΌ νλμ§(λλ νμνμ§ μμμΌ νλμ§) μμ ν λ μ°μ°ν λ°κ²¬νμΌλ©°, λ΄ λͺ©νλ λ·°ν¬νΈ λ³κ²½ μ¬νμ λ΄ λ ΈλΈμ λ¬Άλ κ²μ΄μκ³ μ λ§ μ’μμ κ²μ λλ€ ;)
μ¬κΈ°μ λ΄ μ¬μ© μ¬λ‘λ₯Ό μΆκ°νκ³ μΆμκ³ @IanVS μ²λΌ μ½λ°±λ μ’μμ κ²μ λλ€(λ°λΌμ isMobile μνμ ν κΈνλ©΄ λ·°ν¬νΈ λ³κ²½μ νΈλ¦¬κ±°ν μ μμ)
μ¬λ¬ μ¬λλ€μ΄ μμ‘μ΄ μνλ₯Ό μ λ°μ΄νΈνλ λ°©λ²μ κ΄μ¬μ νλͺ νλ€κ³ λ€μμ΅λλ€. μ°λ¦¬κ° μ’μ μν€ν μ²μ λν΄ λμν μ μλ€λ©΄ μ΄κ²μ΄ λ§μ μ¬λλ€μκ² κ°μΉκ° μμ κ²μ΄λΌκ³ μκ°ν©λλ€. νΉν μ΄κ²μ μ¬λλ€μ΄ μ¬μ© μ¬λΆλ₯Ό μ νν μ μλ μΆκ° κΈ°λ₯μ΄κ³ μ¬μ©νμ§ μμΌλ €λ μ¬λλ€μκ² λΆμ μ μΈ μν₯μ λ―ΈμΉμ§ μκΈ° λλ¬Έμ λλ€.
@Hypnosphi , μ΄μ ꡬνμΈ WDYTμ λν΄ μ΄μκ° μμΌμ ¨λμ?
μ΄ λ¬Έμ λ₯Ό κ³μ 곡κ°νλ €λ©΄ μ¬κΈ°μμ λκΈμ μμ±νμΈμ. λλ μ¬μ ν @Hypnosphi κ° μ΄μ μ μ¬κΈ°μμ μ μν @igor-dvμ λν΄ λ¬΄μμ΄λΌκ³ λ§νλμ§ κΆκΈν©λλ€.
μ μκ°μλ λ€μν μ 보 μμ€λ₯Ό λμ νλ κ²μ΄ μλλΌ κ΅¬μ± μμ μνμ λν λ¨μΌ μ 보 μμ€(λ ΈλΈ)λ₯Ό μ μ§νλλ‘ νμ©νλ κ² κ°μ΅λλ€. λ΄κ° μ μν λ€λ₯Έ λͺ¨λ μ κ·Ό λ°©μ(λνΌ κ΅¬μ± μμ, μν μΆκ° κΈ°λ₯, μ¬κ΅¬μ±)μ μ¬μ€ λ λ€λ₯Έ μμ€λ₯Ό μκ°ν©λλ€. λ΄ μ²΄ν¬λ°μ€ μμ μμλ 체ν¬λ λ ΈλΈλ₯Ό κ°μ§ μ μμΌλ©° λνΌ κ΅¬μ± μμκ° μ²΄ν¬λ μνμ μ 곡νλλ‘ νμ©ν μλ μμ΅λλ€. λλ λ ΈλΈ μ μ΄νμ κ΅¬μ± μμμ λΆλͺ¨λ‘ λ΄ λλ€. λ¨, νμ¬ κ΅¬μ± μμμμ μ½λ°±μ κ°μ Έμ¬ μ μμ΅λλ€. μ΄λ μΌμ’ μ μΌλ°©μ μ΄κ³ λ°μ μ±μ΄ μΌλ°μ μΌλ‘ λΉλλλ λ°©μμ΄ μλλλ€.
λμκ² ν©λ¦¬μ μΌλ‘ λ€λ¦°λ€. APIμ λν΄ λ Όμνμ
μ΄κ²μ νλ₯ν κΈ°λ₯μ΄ λ κ²μ λλ€. λλ λ§€μ° κΈ°λ³Έμ μΈ μ μ΄ κ΅¬μ± μμλ₯Ό μ¬μ©νμ¬ μ¬κΈ°μμ μ΄μ λμΌν μꡬ μ¬νμ μ§λ©΄νμΌλ©° λ€λ₯Έ κ΅¬μ± μμμμλ μ΄μ μ μ§λ©΄νμ΅λλ€. λ΄μ£Όμ μ κ°μ¬ν©λλ€.
νμ¬ κ΅¬λ¬Έμ λ°λΌκ°λ κ²μ μ½κ°μ λμ μ²λΌ 보μ λλ€. μλ§λ λ€μκ³Ό κ°μ΄ μ¬μ©ν μ μμ΅λλ€.
const {value: name, change: setName} = text('Name', 'Kent');
@brunoreis , μμ‘μ΄μ λ°ν μλͺ μ λ³κ²½νλ κ²μ΄ μ£Όμ λ³κ²½ μ¬νμ΄
import {boolean, changeBoolean} from '@storybook/addon-knobs/react';
stories.add('custom checkbox', () => (
<MyCheckbox
checked={boolean('checked', false)}
onChange={(isChecked) => changeBoolean('checked', isChecked)} />
));
onChange
μ½λ°±μ΄ 컀λ§μ νμ©ν μλ μμΌλ―λ‘ λ€μλ μλν©λλ€.
onChange={(isChecked) => changeBoolean('checked')(isChecked)}
// which of course simplifies down to
onChange={changeBoolean('checked')}
μ€μν λΆλΆμ 첫 λ²μ§Έ μΈμκ° λ³κ²½ν΄μΌ νλ λ ΈλΈμ λ μ΄λΈκ³Ό κ°μμΌ νλ€λ κ²μ λλ€. μ΄λ₯Ό ν΅ν΄ μ¬μ©μλ νμ¬ λ ΈλΈκ° μ¬μ©λλ λ°©μμ λ³κ²½νμ§ μκ³ λ μ΄ λμμ μ νν μ μλ€κ³ μκ°ν©λλ€. (λΌλ²¨μ΄ νμ¬ κ³ μ ν νμκ° μλ κ²½μ°κ° μλλΌλ©΄? μλ§λ...)
@IanVS , λ©μ§λ€μ. μλ λ°©μμ λ³κ²½νμ§ μλλ€λ μ μ λμν©λλ€. λ μ΄λΈμ ν€λ‘ μ¬μ©ν μκ°μ νμ§ μμκΈ° λλ¬Έμ λ°©λ²μ μ°Ύμ§ λͺ»νμ΅λλ€. ν¨κ³Όκ° μμ μ μμ΅λλ€. @Hypnosphi κ° λ¬΄μμ μΌλμ λκ³ μλμ§ λ΄ μλ€.
λ ΈλΈμ λ°ν μλͺ μ λ³κ²½νλ κ²μ μ£Όμ λ³κ²½ μ¬νμ λλ€.
κΈ°μ μ μΌλ‘ μ§κΈμ λ¬Έμ κ° λμ§ μμ΅λλ€. 곧 μ£Όμ 릴리μ€κ° μμ΅λλ€. κ·Έλ¬λ μ€μ λ‘ μΌλΆ νμ νΈνμ±μ νμ©νλ κ²μ΄ μ’μ΅λλ€.
λλ μΉ΄λ μ§μμ μμ΄λμ΄λ₯Ό μ’μν©λλ€.
λ μ΄λΈμ΄ νμ¬ κ³ μ ν νμκ° μλ κ²½μ°κ° μλλΌλ©΄?
μ, μ€μ λ‘λ λ€μν μ νμμ κ³ μ ν©λλ€. λ°λΌμ λ³λμ change<Type>
λ΄λ³΄λ΄κΈ°κ° νμνμ§ μμΌλ©° change
μ΄λ©΄ μΆ©λΆν©λλ€. κΈ°λ³Έμ μΌλ‘ https://github.com/storybooks/storybook/pull/3701 μμ λ§λ κ²μ
λλ€.
@aherriot μ΄ κ·νμ λμμΌλ‘ μλ£ν μ μλλ‘ ν΄λΉ PRμ λ€μ μ΄κ² μ΅λλ€.
μ°λ¦¬λ μ΄κ²μ κ°μ§ μ μμ΅λλ€:
const {value: name, change: setName} = text('Name', 'Kent');
text
μ λ°ν μ νμ λ³κ²½ν νμ μμ΄
Javascript ν¨μλ κ°μ²΄μ΄λ―λ‘ μμ±μ κ°μ§ μ μμ΅λλ€.
κ°μ²΄λ₯Ό ꡬ쑰νν μ μμ΅λλ€.
@ndelangen text
ν¨μλ μ€μ λ‘ κ°μ²΄μ΄μ§λ§ λ°ν κ°μ κ·Έλ μ§ μμ΅λλ€. μ΄κ²μ κ·νμ μμμ μλνμ§ μμ΅λλ€.
const { foo, bar } = x() // note the parens
μ°λ¦¬λ λ€μκ³Ό κ°μ κ²μ κ°μ§ μ μμ΅λλ€(μ΄λ¦μ λ Όμμ μ¬μ§κ° μμ΅λλ€):
const {value: name, change: setName} = text.mutable('Name', 'Kent');
μ μ΄κ²μ΄ μλνμ§ μμ΅λκΉ?
const { foo, bar } = x() // note the parens
xμ λ°νμ μμ±λ κ°μ§ μ μλ ν¨μμ λλ€.
λλ λΉμ μ μλ μμμ x = () => {}
μ λν΄ μ΄μΌκΈ°νκ³ μμμ΅λλ€.
text
κ° ν¨μλ₯Ό λ°ννλλ‘ νλ©΄ μ¬μ©μλ μ½λλ₯Ό λ³κ²½ν΄μΌ ν©λλ€.
// Before
<Foo bar={text('Bar', '')}>
// After
<Foo bar={text('Bar', '')()}>
^^ this
μ κ² μ΄μ
μ΄μ λν @IanVS μ μμ
μ΄ κΈ°λ₯μ΄ μμΌλ©΄ μ’μ κ²μ λλ€.
"react hooks"μ κ°μ "destruct"λ μ΄λ»μ΅λκΉ?
const [foo, setFoo] = useString('foo', 'default');
@DimaRGBμ κ°μ λ§μ νλ¬ μμ΅λλ€.
κΈ°μ‘΄ ꡬ문μ μ μ§νκ³ νν¬μ μ μ¬ν νΈμΆμ μΆκ°ν μ μμ΅λλ€. μλ₯Ό λ€λ©΄ λ€μκ³Ό κ°μ΅λλ€.
.add('example', () => {
const [selected, setSelected] = useBool(false);
return <SomeComponent selected={selected} onSelected={setSelected} />
})
λ°μ κ΅¬μ± μμκ° μ체 props
λ₯Ό μ
λ°μ΄νΈν΄μΌ νλ κ²μ΄ μλλΌ λΆλͺ¨μκ² λ³κ²½ν΄μΌ νλ€κ³ μ리λ κ²½μ°κ° μμ΅λλ€. λλ‘λ κ΅¬μ± μμμ μνμ ν κΈν΄μΌ νλ μΌλΆ μμκ° ν¬ν¨λμ΄ μμ΅λλ€(λλ‘λ νμ μμλ₯Ό ν΄λ¦νλ©΄ λ΄κ° κ°μ§κ³ μλ νμ λͺ¨μ λ©λ΄λ₯Ό μ΄μ΄μΌ νκΈ° λλ¬Έμ μ΄ λ¬Έμ κ° λ°μνμ΅λλ€).
@IanVS λλ λΆλͺ¨ μνμ ν΅ν΄μλ§ μ
λ°μ΄νΈλλ ν κΈ κ΅¬μ± μμκ° μκ³ μ€ν 리 λΆ μ€ν 리μ μ¬μ©μκ° ν κΈνλ©΄ UI μνκ° λ
ΈλΈ ν¨λμ νμλ κ²κ³Ό μΌμΉνμ§ μλ μν©μ΄ μμ΅λλ€. @storybook/addons-knobs
μ κ°μΈ λ°©λ²μ μ¬μ©νμ¬ ν΄νΉνμ΅λλ€. λ κ°λ¨ν μ μμ λ€μκ³Ό κ°μ μμ
μ μννλ 곡μ APIλ₯Ό μ 곡νλ κ²μ
λλ€.
import { manager } from '@storybook/addons-knob/dist/registerKnobs.js'
const { knobStore } = manager
// The name given to your knob - i.e: `select("Checked", options, defaultValue)`
knobStore.store['Checked'].value = newValue
// Danger zone! _mayCallChannel() triggers a re-render of the _whole_ knobs form.
manager._mayCallChannel()
@erickwilder κ·νμ μ κ·Ό λ°©μμ μλνμ§λ§ λ ΈλΈ μμμ μ λ°μ΄νΈνμ§ μλ κ² κ°μμ΅λλ€(κ΅¬μ± μμμ μ 곡λ μνμ μ λ°μ΄νΈν κ²½μ°μλ).
νΈμ§νλ€:
κΈλ€; λλ λΆλͺ ν 'μ μ΄λμ§ μλ'λ°©μμΌλ‘ μλνλ νμΈλκ³Ό ν¨κ» options()λ₯Ό μ¬μ©νκ³ μμκΈ° λλ¬Έμ μ λ°μ΄νΈλ₯Ό λ³΄μ§ λͺ»νμ΅λλ€. λ€μ€ μ νμΌλ‘ μ ννκ³ μ½λ°±μμ μ΄ λ°©λ²μ μ¬μ©νμ¬ μ λ°μ΄νΈλ κ°μ λ ΈλΈ νμμΌλ‘ κ°μ Έμμ΅λλ€.
// Ditch when https://github.com/storybooks/storybook/issues/3855 gets resolved properly.
function FixMeKnobUpdate(name, value) {
addons.getChannel().emit(CHANGE, { name, value });
}
λ΄ μ€μ μ μΌλΆ μΈλΆ μ¬νμ μλ΅νμ μ μμ΅λλ€.
κ·Έλ¬ν μ κ·Ό λ°©μμ΄ λͺ¨λ μ¬λμκ² ν¨κ³Όκ° μμμ§ λͺ¨λ₯΄κ² μ΅λλ€.
@IanVSμ μ μ μΌλ‘ λμν©λλ€. μ λ μ€ν 리λΆμ μ’μνμ§λ§ μ‘μ μ ν΅ν΄ λ ΈλΈλ₯Ό μ λ°μ΄νΈνλ κΈ°λ₯μ΄ μ λ§ κ·Έλ¦¬μμ. μ κ²½μ°μλ λ κ°μ κ°λ³ κ΅¬μ± μμ Aμ Bκ° μμ§λ§ μ μ΄μΌκΈ° μ€ νλμμλ λ κ΅¬μ± μμλ₯Ό λͺ¨λ μ¬μ©νμ¬ κ΅¬μ±μ 보μ¬μ£Όκ³ μΆμ΅λλ€. κ·Έλμ AIλ₯Ό λ³κ²½ν λλ§λ€ Bλ₯Ό μμ νκ³ κ·Έ λ°λλ λ§μ°¬κ°μ§μ λλ€.
λ΄ μ€μ (Angular 7)μΌλ‘ @erickwilder μ ν΄νΉμ μλνμ§λ§ λ ΈλΈ μ μ₯μλ₯Ό μ λ°μ΄νΈνλ €κ³ ν λλ§λ€ λ€μ μ€λ₯κ° λ°μν©λλ€.
μ€λ₯: Angular Zoneμ μμ κ²μΌλ‘ μμλμ§λ§ μ€μ λ‘ μμ΅λλ€!
μ΄λ»κ²λ μ΄κ²μ Angular μΈλΆμμ μ€ννλ €κ³ μλνμ§λ§ ν μ μμμ΅λλ€... μ΅μ μ μλ리μ€μμλ Aμ Bμ λνΌκ° λ μΈ λ²μ§Έ κ΅¬μ± μμ Cλ₯Ό λ§λ€ κ²μ λλ€.
μ΄ (λ°μ, κ°λ, VUE, μ무κ²λ)νμ§λ§ λ ΈλΈ λΆκ° κΈ°λ₯μ λ€μ λ λλ§μ νλ μ μν¬ / λΌμ΄λΈλ¬λ¦¬μ κ΄λ ¨λμ§ μλ @davidolivefarga @erickwilderμμ μμ λ°©νΈμ νλ μ μν¬μ λν΄ μλν©λλ€.
μμμ μΈκΈ
+1μ λ ΈλΈ μ΄λ¦μ μ λ°μ΄νΈν λ¬Έμμ΄λ‘ ν¬ν¨νκ³ μ κ°μ ν¬ν¨νλ νΈλ¦¬κ±°μ 곡κ°μ μΌλ‘ νμλλ λ©μλλ₯Ό μΆκ°ν©λλ€. μλ₯Ό λ€λ©΄ λ€μκ³Ό κ°μ΅λλ€.
import { manager } from "@storybook/addon-knobs"
manager.updateKnob(
propName, // knobs property, example from above "Checked"
newValue, // new value to set programmatically, ex. true
)
λλ μ΄κ²μ΄ 곡μμ μΌλ‘ μ§μλκΈ°λ₯Ό μ λ§λ‘ μν©λλ€.
κ·Έ λμ Storybook v5λ₯Ό μ¬μ©νμ¬ λ€μκ³Ό κ°μ λμ°ν ν΄ν€ μ루μ μ μ¬μ©ν΄μΌ νμ΅λλ€.
window.__STORYBOOK_ADDONS.channel.emit('storybookjs/knobs/change', {
name: 'The name of my knob',
value: 'the_new_value'
})
π
π
κ΄λ ¨: #6916
μ΄κ²μ λ©μ§ κ²μ λλ€ ... νΉν λͺ¨λ¬ λλ¬Έμ λλ€.
λλ μ΄κ²μ΄ μ μ©ν κ²μ΄λΌκ³ μκ°νλ€.
μμ:
storiesOf('input', module)
.addDecorator(withKnobs)
.add('default', () => <input type={text('type', 'text')} value={text('value', '')} disabled={boolean('disabled', false)} placeholder={text('placeholder', '')} onChange={action('onChange')} />)
μ΄κ²μ νμ¬ μλνμ§λ§ ν μ€νΈλ μμμ propsμ μ€μ λ κ°μ onChange μ΄λ²€νΈ λμ κ°μ μ°κ²°νλ €λ κ²μ΄ λΉμ°ν΄ 보μ λλ€. μ΄κ²μ μμμ μ μ©μ λ μ 보μ¬μ€ κ²μ λλ€.
μ΄κ²μ μ μ© ν κ²μ λλ€
μ¬κΈ°μμ μ루μ μ κ°λ¦¬ν€λ @mathieuk/ @raspo μ +1.
μ°λ¦¬λ μ μ¬μ μΌλ‘ λ€λ₯Έ λ°©λ²μΌλ‘λ μ΄κ²μ μ κ·Όν μ μμ΅λλ€. helpers
λͺ¨λμμ λͺ κ°μ§ μΌλ° λ©μλλ₯Ό μμ±νμκ² μ΅λκΉ?
import addons from "@storybook/addons";
export const emitter = (type, options) => addons.getChannel().emit(type, options);
export const updateKnob = (name, value) => (
emitter("storybookjs/knobs/change", { name, value })
);
κ·Έλ¦¬κ³ μ΄μΌκΈ°μμ νμμ λ°λΌ μ ν...
import { text } from "@storybook/addon-knobs";
import { updateKnob } from 'helpers';
// ...
const value = text("value", "Initial value");
<select
value={value}
onChange={({ target }) => updateKnob("value", target.value)}
>
...νμ§λ§ μ¬μ ν λ ΈλΈ APIμ λ΄μ₯λ μ μλ 무μΈκ°μ λν νν€ν μλ°©ν₯ λ°μΈλ© ν΄κ²° λ°©λ²μ²λΌ λκ»΄μ§λλ€.
μμ μ λ°μ΄νΈκ° μμ΅λκΉ? λ§€μ° μ μ©ν κΈ°λ₯μ΄ λ κ²μ λλ€ π
ꡬνλλ μ΄ κΈ°λ₯μ μ¬μ©νλ©΄ λ§€μ° κ°λ ₯ν μνΈ μ’ μ λ ΈλΈλ₯Ό μμ£Ό μ½κ² μνν μ μμ΅λλ€. μ€ν 리μμ λ€μκ³Ό κ°μ΄ νλμ λ ΈλΈκ° λ€λ₯Έ λ ΈλΈμ λ°λΌ λμ μΌλ‘ μ λ°μ΄νΈλλλ‘ ν μ μλ€λ©΄ νμ΄μ§ λ§€κΉ κ΅¬μ± μμ μ€ν 리λ₯Ό λ§λλ κ²μ μμν΄ λ³΄μμμ€.
const resultsCount = number(
'Results count',
currentPage, {
max: 100,
min: 0,
range: true
}
);
const resultsArray: React.ReactNode[] = new Array(resultsCount)
.fill(true)
.map((_, idx) => <div key={idx + 1}>Test Pagination Result #{idx + 1}</div>);
const childrenPerPage = 10;
const currentPage = number(
'Current page index',
0, {
max: Math.ceil(resultsCount / childrenPerPage) - 1,
min: 0,
range: true
}
);
κΈ°λ³Έμ μΌλ‘ currentPage
λ
ΈλΈμ μ΅λ λ²μκ° resultsCount
λ
ΈλΈλ₯Ό 10μ© μ¦κ°μν¬ λ λμ μΌλ‘ μ
λ°μ΄νΈλκΈ°λ₯Ό ν¬λ§νλ©΄μ μ΄ μμ
μ μλνμ§λ§ κ° λ
ΈλΈμ μ΄κΈ° κ°μΌλ‘ 보μ
λλ€. μμ± μ μΊμλκ³ νμ λ λλ§μμ λ΄λΆ μν κ°μ μ¬μ μνλ λ° μ¬μ©λμ§ μμ΅λλ€. λλμ΄ μ¦κ° ν λ μμ μ½λλ‘ resultsCount
λ΄κ° κΈ°λ 10+μ μν΄ max
μ currentPage
κΈ°λ³Έ κ°μλ λΆκ΅¬νκ³ , λν 1 μ¦κ° ν μνμ§λ§ κ·Έ κ°μΉμ μλ° λμΌ λ³κ²½λ κ°μ κ³μ°νλ λ° μ¬μ©λ©λλ€( Math.ceil(resultsCount / childrenPerPage) - 1
λ‘κΉ
μ μμλλ μ κ°μ 보μ¬μ€λλ€).
μ°λ¦¬λ 5.3(1μ μ΄ λ¦΄λ¦¬μ€)μ κ±°μ λλ΄κ³ 6.0(3μ λ§ λ¦΄λ¦¬μ€)μ λν λ ΈλΈ μ¬μμ±μ μ‘°μ¬νμ¬ μ¬λ¬ κ°μ§ μ€λλ λ ΈλΈ λ¬Έμ λ₯Ό ν΄κ²°ν κ²μ λλ€. μ΄ μμ μ μνν μ μλμ§ μμλ³΄κ² μ΅λλ€! κΈ°λ€λ € μ£Όμ μ κ°μ¬ν©λλ€!
@shilman μ΄ κΈ°λ₯μ λν΄ λ§€μ° κΈ°λνκ³ μμ΅λλ€ π
μ , @atanasster & @PlayMa256 μ μ΄λ₯Ό μν κΈ°λ°μ νλμ μμ ν΄ μμ΅λλ€. μ λλ‘ νλ €λ©΄ λͺ λ² λ λ°λ³΅ν΄μΌ νμ§λ§ 6.0.0μμ 100%λ₯Ό λ¬μ±νκ³ μ€ν 리λΆμ λ°μ΄ν° λ° λ°μμ±μ νλͺ μ μΌμΌν¬ μ μλ€κ³ λ§€μ° νμ ν©λλ€.
νλͺ μ μΌμΌν€λ€? λ¨κ±°μ΄ λ§ν digity. κ·Έλ§ λλ €, λ΄ λͺΈμ μ€λΉλμ΄
λͺ¨λ¬μ κ²½μ° +1 :)
μ²μλΆν° λΆκ°λ₯νλ€λ κ²μ΄ λ―ΏκΈ°μ§ μμ΅λλ€. μ λ°μ΄νΈλ₯Ό κΈ°λ€λ¦¬λ μ€...
μλ
μ¬λ¬λΆ!
μμ μ루μ
μΌλ‘ λ΄ μ± λ€μ μ½λμμ μ¬μ©νμ΅λλ€.
import { addons } from '@storybook/addons';
import { CHANGE } from '@storybook/addon-knobs';
const channel = addons.getChannel();
channel.emit(CHANGE, {
name: 'prop_name',
value: prop_value,
});
μμ§ μ΄ κΈ°λ₯μ΄ κΈ°λ³Έμ μΌλ‘ ꡬνλκΈ°λ₯Ό κΈ°λ€λ¦¬κ³ μμ΅λλ€.
Observableμ μ¬μ©νμ¬ κ·Έ λ¬Έμ λ₯Ό ν΄κ²°νμ΅λλ€. λλ Angularμ ν¨κ» μ€ν 리 λΆμ μ¬μ©νκ³ μμ΅λλ€.
`
.add('μ°¨νΈ λ°μ΄ν° μ
λ°μ΄νΈ μ€', () => {
const myObservable= new BehaviorSubject([{a: 'a', b: 'b'}]);
return {
template: '
<my-component
myInput: myData,
(myEvent)="myEventProp($event)"
></my-component>
',
props: {
myData: myObservable,
myEventProp: $event => {
myObservable.next([]);
action('(myEvent)')($event);
}
}
};
})
`
@norbert-doofus λλΆμ μμ κ° λμμ΄ λμμ΅λλ€ π
μλ κ°±, μ°λ¦¬λ 6.0-λ² νμμ μ λμ¨ μ»¨νΈλ‘€μ μΆμνμ΅λλ€!
컨νΈλ‘€μ μ₯κΈ°μ μΌλ‘ μ λμ¨ λ ΈλΈλ₯Ό λ체νκΈ° μν ν΄λμ© μλ μμ± λ ΈλΈμ λλ€.
μ€λ μ κ·Έλ μ΄λνμ¬ μ¬μ©ν΄ 보μμμ€. μ΄ μμ ν λ²μ μ μΆμν μ μλλ‘ λμμ£Όμ μ κ°μ¬ν©λλ€!
λλ¨ν΄! READMEλ₯Ό μ½κ³ λ μ μ μμ΅λλ€(λ΄κ° λμ³€μ μλ μμ). μ΄ μλ‘μ΄ controls
νλ‘κ·Έλλ° λ°©μμΌλ‘ λ³κ²½ν μ μμ΅λκΉ? μ΄ λ¬Έμ μμ μμ²ν λ΄μ©μ 무μμ
λκΉ?
APIκ° μμ§ κ³΅μμ μΌλ‘ μ§μλλμ§ νμ ν μλ μμ§λ§ κ°λ₯ν©λλ€. μ λ @tmeasday μ
updateArgs
λ₯Ό μΆκ°νμκ² μ΅λκΉ?this.context?.updateArgs(....)
)Controlsμ κ΄μ¬μ΄ μμ§λ§ μ΄λμλΆν° μμν΄μΌ ν μ§ λͺ¨λ₯΄λ μ¬λμ μν΄ μλ‘μ΄ CRA νλ‘μ νΈμμ μ€μ λ°λͺ¨λ‘ μ΄λνλ λΉ λ₯΄κ³ κ°λ¨ν λ¨κ³λ³ μ°μ΅μ λ§λ€μμ΅λλ€. νμΈ ν΄λ΄:
=> CRA λ° TypeScriptκ° ν¬ν¨λ μ€ν λ¦¬λΆ μ»¨νΈλ‘€
Controls READMEμλ "knob to controls" λ§μ΄κ·Έλ μ΄μ λ¬Έμλ μμ΅λλ€.
=> μ λμ¨ λ ΈλΈμμ μ΄λ»κ² λ§μ΄κ·Έλ μ΄μ ν©λκΉ?
μλ μ¬λ¬λΆ!
μμ μ루μ μΌλ‘ λ΄ μ± λ€μ μ½λμμ μ¬μ©νμ΅λλ€.import { addons } from '@storybook/addons'; import { CHANGE } from '@storybook/addon-knobs'; const channel = addons.getChannel(); channel.emit(CHANGE, { name: 'prop_name', value: prop_value, });
μμ§ μ΄ κΈ°λ₯μ΄ κΈ°λ³Έμ μΌλ‘ ꡬνλκΈ°λ₯Ό κΈ°λ€λ¦¬κ³ μμ΅λλ€.
groupId
λ₯Ό μ¬μ©ν λ λ€μκ³Ό κ°μ΄ name
κ·Έλ£Ή IDλ₯Ό μΆκ°ν΄μΌ ν©λλ€.
const show = boolean('Show Something', true, 'Group')
channel.emit(CHANGE, {
name: 'Show Something_Group',
value: prop_value,
});
λν channel
λ EventEmitterμ΄λ―λ‘ addListener
μμ λλ 맀κ°λ³μκ° λ¬΄μμΈμ§ νμΈν μ μμ΅λλ€.
channel.addListener(CHANGE, console.log)
λ€μμ v6μμ addon-controls
λ₯Ό μ¬μ©νμ¬ μ΄ μμ
μ μννλ λ°©λ²μ κ΄μ¬μ΄ μλ μ¬λμ μν μ½λμ
λλ€.
import { useArgs } from '@storybook/client-api';
// Inside a story
export const Basic = ({ label, counter }) => {
const [args, updateArgs] = useArgs();
return <Button onClick={() => updateArgs({ counter: counter+1 })>{label}: {counter}<Button>;
}
μ΄κ²μ΄ μ΄ λͺ©μ μ κ°μ₯ μ ν©ν APIμΈμ§λ λͺ¨λ₯΄κ² μ§λ§ μλν΄μΌ ν©λλ€. λͺ¨λ Έλ ν¬μ μ:
@shilmanλ, κ°μ¬ν©λλ€! κ·Έκ² νΈλ¦μ νλ€.
κ΄μ¬ μλ μ¬λλ€μ μν΄ μ΄ μ 체 μ€λ λλ₯Ό μμν μ νν Checkbox
μ€ν 리 checked
μνμ΄ μμ΅λλ€. Storybook 6.0.0-rc.9λ₯Ό μ¬μ©νμ¬ μλ‘ μ°κ²°λ μ΄μΌκΈ°λ λ€μκ³Ό κ°μ΅λλ€.
export const checkbox = (args) => {
const [{ checked }, updateArgs] = useArgs();
const toggleChecked = () => updateArgs({ checked: !checked });
return <Checkbox {...args} onChange={toggleChecked} />;
};
checkbox.args = {
checked: false,
label: 'hello checkbox!',
};
checkbox.argTypes = {
checked: { control: 'boolean' },
};
@shilman μ μ΄λ ν
μ€νΈ μ
λ ₯μ μν΄ μ€ν 리μμ useArgs
λ₯Ό νμ©νλ €κ³ μλνμ΅λλ€(μΌλ°μ μΌλ‘ useState
νν¬λ₯Ό μ¬μ©νμ¬ λ€μμ ν΅ν΄ ꡬμ±μμμ value
μνμ μ
λ°μ΄νΈν μ μλ κ²½μ° onChange
μ΄λ²€νΈ). κ·Έλ¬λ μ¬μ©μκ° λ¬Έμλ₯Ό μ
λ ₯ν λλ§λ€ κ΅¬μ± μμκ° ν¬μ»€μ€λ₯Ό μλ λ¬Έμ κ° λ°μνμ΅λλ€. argsλ₯Ό μ
λ°μ΄νΈν λλ§λ€ μ€ν 리λ₯Ό μλ‘ κ³ μΉκ±°λ λ€μ λ λλ§νκΈ° λλ¬ΈμΌκΉμ?
μ μ΄λ ν μ€νΈ μ λ ₯μ΄ μλ κ΅¬μ± μμμ λν΄ μΈμ/컨νΈλ‘€μ μ¬μ©νλ λ° κΆμ₯λλ λ€λ₯Έ λ°©λ²μ΄ μμ΅λκΉ?
μ΄κ²μ 6.0.0-rc.13μ΄μμ΅λλ€.
@jcq μ¬νμΌλ‘ μ λ¬Έμ λ₯Ό λ§λ€ μ μμ΅λκΉ? μ΄κ²μ useArgs
μ μ£Όμ μ¬μ© μ¬λ‘λ μλμμ§λ§ νμ€ν μ§μνκ³ μΆμ μ¬λ‘μ΄λ―λ‘ κΈ°κΊΌμ΄ μμΈν μ΄ν΄λ³΄κ² μ΅λλ€.
@shilman λ¬Έμ μμ β μ¬κΈ°μ μλ‘μ΄ λ¬Έμ κ° μμ΅λλ€.
https://github.com/storybookjs/storybook/issues/11657
λν μλͺ»λ λμμ΄ λ¬Έμμμλ νμλμ§λ§ μΌλ° μΊλ²μ€ λͺ¨λμμλ μ¬λ°λ₯΄κ² μλνλ€λ μ μ λΆλͺ ν νμ΄μΌ νμ΅λλ€.
Observableμ μ¬μ©νμ¬ κ·Έ λ¬Έμ λ₯Ό ν΄κ²°νμ΅λλ€. λλ Angularμ ν¨κ» μ€ν 리 λΆμ μ¬μ©νκ³ μμ΅λλ€.
`
.add('μ°¨νΈ λ°μ΄ν° μ λ°μ΄νΈ μ€', () => {const myObservable= new BehaviorSubject([{a: 'a', b: 'b'}]); return { template: ' <my-component myInput: myData, (myEvent)="myEventProp($event)" ></my-component> ', props: { myData: myObservable, myEventProp: $event => { myObservable.next([]); action('(myEvent)')($event); } } };
})
`
μ΄κ²μ Angularλ₯Ό μ¬μ©νμ¬ λλ₯Ό μν΄ μΌνμ§λ§ 5 νμμ myData.value
λ³κ²½νμ΅λλ€.
λλ μ΄κ²μ μμ§ μλνμ§ μμμ§λ§(μ§κΈμ μ΄μ λ²μ μ μ€ν 리λΆμ κ³ μ λμ΄ μμ) μ΄ λ¬Έμ λ₯Ό μ§κΈ μ’ λ£ν μ μλ κ² κ°μ΅λλ€. args/controlsμ λν νλ₯ν μμ μ κ°μ¬λ립λλ€!
κ°μ₯ μ μ©ν λκΈ
μ°λ¦¬λ 5.3(1μ μ΄ λ¦΄λ¦¬μ€)μ κ±°μ λλ΄κ³ 6.0(3μ λ§ λ¦΄λ¦¬μ€)μ λν λ ΈλΈ μ¬μμ±μ μ‘°μ¬νμ¬ μ¬λ¬ κ°μ§ μ€λλ λ ΈλΈ λ¬Έμ λ₯Ό ν΄κ²°ν κ²μ λλ€. μ΄ μμ μ μνν μ μλμ§ μμλ³΄κ² μ΅λλ€! κΈ°λ€λ € μ£Όμ μ κ°μ¬ν©λλ€!