+
-
- {
/>
)
-}
+})
export default {
component: SelectionWidgetV2,
+ decorators: [withParticipationThemeUi],
+ argTypes: {
+ isStatic: {
+ type: "boolean",
+ }
+ }
}
const StickToBottom = ({ children }) => (
@@ -101,5 +109,7 @@ const Template = (args) => {
export const Interactive = Template.bind({})
Interactive.args = {
+ isStatic: true,
+ isAccessible: true,
math: mathResult,
}
diff --git a/stories/compdem/client-participation/CivicTechTO/TidCarouselV2.js b/stories/compdem/client-participation/CivicTechTO/TidCarouselV2.js
deleted file mode 100644
index 6ae9c05..0000000
--- a/stories/compdem/client-participation/CivicTechTO/TidCarouselV2.js
+++ /dev/null
@@ -1,97 +0,0 @@
-import React from 'react'
-import { animated, useTransition } from '@react-spring/web'
-import useMeasure from 'react-use-measure'
-
-export const TidCarouselButton = ({ label, isShown, isSelected, handleClick, containerWidth }) => {
- const transition = useTransition(isShown, {
- from: {
- width: 0,
- marginRight: 0,
- opacity: 1,
- },
- enter: {
- width: containerWidth/5-5,
- marginRight: 0,
- opacity: 1,
- },
- leave: {
- width: 0,
- marginRight: -5,
- opacity: 0,
- },
- })
- return (
- transition((style, isShownTransition) => (
- isShownTransition &&
-
- {label}
-
-
- ))
- )
-}
-
-const TidCarouselV2 = ({
- selectedTidCuration,
- allComments,
- commentsToShow,
- selectedComment,
- handleCommentClick,
- Strings,
-}) => {
- if ( selectedTidCuration === null ) return null
- const [ref, bounds] = useMeasure()
-
- allComments = allComments.sort((a, b) => a.tid - b.tid)
- const commentsToShowTids = commentsToShow.map(c => c.tid)
-
- // ref not available on first render, so only render map after bounds exists.
- return (
-
- {!bounds.width || allComments.map((c, i) => (
- handleCommentClick(c)}
- isSelected={selectedComment && selectedComment.tid === c.tid}
- isShown={commentsToShowTids.includes(c.tid)}
- />
- ))}
-
- )
-}
-
-export default TidCarouselV2
diff --git a/stories/compdem/client-participation/CivicTechTO/TidCarouselV2Animated.js b/stories/compdem/client-participation/CivicTechTO/TidCarouselV2Animated.js
new file mode 100644
index 0000000..484ecfe
--- /dev/null
+++ b/stories/compdem/client-participation/CivicTechTO/TidCarouselV2Animated.js
@@ -0,0 +1,174 @@
+/** @jsx jsx */
+import { jsx, Box } from 'theme-ui'
+
+import React from 'react'
+import * as Tabs from "@radix-ui/react-tabs"
+import { animated, useTransition } from '@react-spring/web'
+import useMeasure from 'react-use-measure'
+
+const AnimatedBox = animated(Box)
+
+function usePrevious(value) {
+ const ref = React.useRef();
+ React.useEffect(() => {
+ ref.current = value; //assign the value of ref to the argument
+ },[value]); //this code will run when the value of 'value' changes
+ return ref.current; //in the end, return the current ref value.
+}
+
+export const TidCarouselButton = React.forwardRef(({ label, isShown, isSelected, handleClick, containerWidth, style, ...rest }, ref) => {
+ // Allows selected style to persist during transition out.
+ let wasSelected = usePrevious(isSelected)
+
+ const styles = {
+ button: {
+ ...style,
+ padding: 0,
+ overflow: "hidden",
+ fontSize: 14,
+ letterSpacing: 0.75,
+ // Only want to style based on previous select state when
+ // a button is no longer shown (aka on its was out)
+ variant: (isSelected || (wasSelected && !isShown)) ? "buttons.primary" : "buttons.secondary",
+ textShadow: (isSelected || (wasSelected && !isShown)) ? "0 0 .65px white" : null,
+ },
+ span: {
+ // 1s is rought estimate, but react-spring uses forces, not duration.
+ transition: "transform 1s ease-in-out",
+ transform: isShown ? "scaleX(1)" : "scaleX(0.5)",
+ // Needed in order to transform.
+ display: "inline-block",
+ },
+ }
+ const transition = useTransition(isShown, {
+ from: {
+ width: 0,
+ marginRight: 0,
+ opacity: 1,
+ },
+ enter: {
+ // TODO: Why is this such a funny number? Would expect 4 to work.
+ width: containerWidth/5-4.8,
+ marginRight: 0,
+ opacity: 1,
+ },
+ leave: {
+ width: 0,
+ marginRight: -5,
+ opacity: 0,
+ },
+ })
+ return (
+ transition((style, isShownTransition) => (
+ isShownTransition &&
+
+ {label}
+
+
+ ))
+ )
+})
+
+const TidCarouselV2Animated = React.forwardRef(({
+ selectedTidCuration,
+ allComments,
+ commentsToShow,
+ selectedComment,
+ handleCommentClick,
+ isAccessible = false,
+ Strings,
+}, ref) => {
+ // TODO: Why doesn't this line avoid infinite renders when null?
+ if ( selectedTidCuration === null ) return null
+ // TODO: If we ever need to use the forwardRef, we'll need another package.
+ // See: https://github.com/pmndrs/react-use-measure?tab=readme-ov-file#multiple-refs
+ const [localRef, bounds] = useMeasure()
+
+ allComments = allComments.sort((a, b) => a.tid - b.tid)
+
+ const buttonHeight = 25
+ const gap = 5
+ const getRows = cols => {
+ const maxStatements = 10
+ return Math.ceil(maxStatements/cols)
+ }
+ // Example: calc(20%-4px)
+ const getButtonWidthCalc = cols => `calc(${100/cols}% - ${gap*((cols-1)/cols)}px)`
+ const getContainerHeight = cols => buttonHeight*getRows(cols) + gap*(getRows(cols)-1)
+
+ const styles = {
+ container: {
+ height: getContainerHeight(5),
+ display: "flex",
+ flexWrap: "wrap",
+ gap: `${gap}px`,
+ justifyContent: "flex-start",
+ marginRight: -30,
+ },
+ button: {
+ height: buttonHeight,
+ // flex: `1 0 ${getButtonWidthCalc(5)}`,
+ // maxWidth: getButtonWidthCalc(5),
+ },
+ }
+
+ return (
+ // padding and margins here are to ensure focus glow is visible with overflow: hidden.
+
+ {isAccessible
+ ? (
+
+
+ {!bounds.width || allComments.map(c => (
+
+ cts.tid == c.tid)}
+ />
+
+ ))}
+
+ {/* {commentsToShowTids.map(tid => (
+ Statement {tid}...
+ ))} */}
+
+ )
+ : (
+
+ {/* ref not available on first render, so only render map after bounds exists. */}
+ {!bounds.width || allComments.map(c => (
+ cts.tid == c.tid)}
+ />
+ ))}
+
+ )
+ }
+
+ )
+})
+
+export default TidCarouselV2Animated
diff --git a/stories/compdem/client-participation/CivicTechTO/TidCarouselV2.stories.js b/stories/compdem/client-participation/CivicTechTO/TidCarouselV2Animated.stories.js
similarity index 74%
rename from stories/compdem/client-participation/CivicTechTO/TidCarouselV2.stories.js
rename to stories/compdem/client-participation/CivicTechTO/TidCarouselV2Animated.stories.js
index fd56fa2..29cf7fe 100644
--- a/stories/compdem/client-participation/CivicTechTO/TidCarouselV2.stories.js
+++ b/stories/compdem/client-participation/CivicTechTO/TidCarouselV2Animated.stories.js
@@ -2,16 +2,19 @@ import React from 'react'
import { action } from '@storybook/addon-actions'
import Strings from '../../../../codebases/compdem/client-participation/js/strings/en_us'
import { getComments, getMath } from '../../../../.storybook/utils'
-import TidCarouselV2 from './TidCarouselV2'
+import TidCarouselV2Animated from './TidCarouselV2Animated'
+import { withParticipationThemeUi } from '../../../../.storybook/decorators'
const mathResult = getMath()
const commentsData = getComments()
-commentsData.sort((a,b) => a.tid - b.tid)
export default {
- component: TidCarouselV2,
+ component: TidCarouselV2Animated,
+ decorators: [withParticipationThemeUi],
argTypes: {
selectedTidCuration: {
+ // TODO: Figure out why null does infinite renders.
+ // options: [null, 'majority', 0, 1, 2, 3],
options: ['majority', 0, 1, 2, 3],
control: { type: 'inline-radio' },
},
@@ -30,7 +33,7 @@ const Template = (args) => {
}
)
- const handleCommentClick = (c) => {
+ const handleCommentClick = (c) => () => {
setSelectedComment(c)
action("Clicked")(c)
}
@@ -41,7 +44,7 @@ const Template = (args) => {
if (!commentsToShow.map(c => c.tid).includes(selectedComment?.tid)) {
handleCommentClick(commentsToShow[0])
}
- return
{
export const Interactive = Template.bind({})
Interactive.args = {
+ isAccessible: true,
selectedTidCuration: 1,
allComments: commentsData,
Strings,
diff --git a/stories/compdem/client-participation/CivicTechTO/TidCarouselV2Static.js b/stories/compdem/client-participation/CivicTechTO/TidCarouselV2Static.js
new file mode 100644
index 0000000..a57af0f
--- /dev/null
+++ b/stories/compdem/client-participation/CivicTechTO/TidCarouselV2Static.js
@@ -0,0 +1,97 @@
+/** @jsx jsx */
+import { jsx, Box } from 'theme-ui'
+import * as Tabs from "@radix-ui/react-tabs"
+
+import React from "react"
+
+const TidCarouselButton = React.forwardRef(({ isSelected, handleClick, style, children, ...rest }, ref) => {
+ const styles = {
+ button: {
+ ...style,
+ fontSize: 14,
+ letterSpacing: 0.75,
+ variant: isSelected ? "buttons.primary" : "buttons.secondary",
+ textShadow: isSelected ? "0 0 .65px white" : null,
+ }
+ }
+ return (
+
+ {children}
+
+ )
+})
+
+const TidCarouselV2Static = React.forwardRef(({
+ selectedTidCuration,
+ // allComments,
+ commentsToShow,
+ selectedComment,
+ handleCommentClick,
+ isAccessible = false,
+ Strings,
+}, ref) => {
+ commentsToShow.sort((a, b) => a.tid - b.tid)
+
+ const buttonHeight = 25
+ const gap = 5
+ const getRows = cols => {
+ const maxStatements = 10
+ return Math.ceil(maxStatements/cols)
+ }
+ // Example: calc(20%-4px)
+ const getButtonWidthCalc = cols => `calc(${100/cols}% - ${gap*((cols-1)/cols)}px)`
+ const getContainerHeight = cols => buttonHeight*getRows(cols) + gap*(getRows(cols)-1)
+ const styles = {
+ container: {
+ height: [getContainerHeight(5), getContainerHeight(10)],
+ display: "flex",
+ flexWrap: "wrap",
+ gap: `${gap}px`,
+ justifyContent: "flex-start",
+ },
+ button: {
+ height: buttonHeight,
+ flex: [`1 0 ${getButtonWidthCalc(5)}`, `1 0 ${getButtonWidthCalc(10)}`],
+ maxWidth: [getButtonWidthCalc(5), getButtonWidthCalc(10)],
+ },
+ }
+ return (
+ isAccessible
+ ? (
+
+
+
+ {commentsToShow.map(c => (
+
+
+
+ ))}
+
+ {/* {commentsToShowTids.map(tid => (
+ Statement {tid}...
+ ))} */}
+
+
+ )
+ : (
+
+ {commentsToShow.map(c => (
+
+ ))}
+
+ )
+ )
+})
+
+export default TidCarouselV2Static
diff --git a/stories/compdem/client-participation/CivicTechTO/TidCarouselV2Static.stories.js b/stories/compdem/client-participation/CivicTechTO/TidCarouselV2Static.stories.js
new file mode 100644
index 0000000..32dcba0
--- /dev/null
+++ b/stories/compdem/client-participation/CivicTechTO/TidCarouselV2Static.stories.js
@@ -0,0 +1,129 @@
+import React, { useState } from 'react'
+import { action } from '@storybook/addon-actions'
+import TidCarouselV2Static from './TidCarouselV2Static'
+import * as globals from '../../../../codebases/compdem/client-participation/vis2/components/globals'
+import Strings from '../../../../codebases/compdem/client-participation/js/strings/en_us'
+import { getMath, getComments } from '../../../../.storybook/utils'
+import { withParticipationThemeUi } from '../../../../.storybook/decorators'
+
+const mathResults = getMath()
+const commentsData = getComments()
+
+const pluckNBetweenLowerUpper = (n, lower, upper) => {
+ let numbers = []
+ while (numbers.length < n) {
+ let candidate = Math.floor(Math.random() * (upper - lower)) + (lower + 1)
+ if (!numbers.includes(candidate)) {
+ numbers.push(candidate)
+ }
+ }
+ // Ascending integer sort.
+ numbers.sort((a, b) => a - b)
+
+ return numbers
+}
+
+export default {
+ component: TidCarouselV2Static,
+ decorators: [withParticipationThemeUi],
+}
+
+const Template = (args) => {
+ const [selectedComment, setSelectedComment] = useState(null)
+
+ const handleCommentClick = (comment) => () => {
+ action("Clicked")(comment)
+ setSelectedComment(comment)
+ }
+
+ const commentsByGroup = Object.assign({},
+ mathResults.repness,
+ {
+ "majority": [
+ ...mathResults.consensus.agree,
+ ...mathResults.consensus.disagree,
+ ],
+ }
+ )
+ const commentsToShow = commentsData
+ .filter(c => commentsByGroup[args.selectedTidCuration]
+ ?.map(i => i.tid).includes(c.tid)
+ )
+
+ return
+}
+
+export const Interactive = Template.bind({})
+Interactive.args = {
+ isAccessible: true,
+ selectedTidCuration: 0,
+ Strings,
+}
+Interactive.argTypes = {
+ selectedTidCuration: {
+ options: [null, 'majority', 0, 1, 2, 3],
+ control: { type: 'inline-radio' },
+ },
+}
+
+export const Empty = Template.bind({})
+Empty.args = {
+ isAccessible: true,
+ commentsToShow: [],
+ selectedTidCuration: null,
+ selectedComment: null,
+ // TODO: Pretty sure this is janky. It should be simply action("Clicked")
+ // and the prop in tidCarousel should be:
+ // onClick={() => this.props.handleCommentClick(c)}
+ // not just
+ // onClick={this.props.handleCommentClick(c)}
+ handleCommentClick: (c) => () => action("Clicked")(c),
+ Strings,
+}
+
+export const OneStatement = Template.bind({})
+OneStatement.args = {
+ ...Empty.args,
+ commentsToShow: commentsData.slice(10,11),
+}
+
+export const FiveStatements = Template.bind({})
+FiveStatements.args = {
+ ...Empty.args,
+ commentsToShow: commentsData.slice(10,15),
+}
+
+export const SixStatements = Template.bind({})
+SixStatements.args = {
+ ...Empty.args,
+ commentsToShow: commentsData.slice(10,16),
+}
+
+export const TenStatements = Template.bind({})
+TenStatements.args = {
+ ...Empty.args,
+ commentsToShow: commentsData.slice(10,20),
+}
+
+export const Selected = Template.bind({})
+Selected.args = {
+ ...Empty.args,
+ commentsToShow: commentsData.slice(10,20),
+ selectedComment: commentsData[11],
+}
+
+export const UpToDoubleDigits = Template.bind({})
+UpToDoubleDigits.args = {
+ ...Empty.args,
+ commentsToShow: pluckNBetweenLowerUpper(10, 0, 100).map(i => ({ tid: i })),
+}
+
+export const UpToTripleDigits = Template.bind({})
+UpToTripleDigits.args = {
+ ...Empty.args,
+ commentsToShow: pluckNBetweenLowerUpper(10, 0, 400).map(i => ({ tid: i })),
+}
diff --git a/stories/compdem/client-participation/TidCarousel.stories.js b/stories/compdem/client-participation/TidCarousel.stories.js
index dbf4751..fa7e7c6 100644
--- a/stories/compdem/client-participation/TidCarousel.stories.js
+++ b/stories/compdem/client-participation/TidCarousel.stories.js
@@ -6,8 +6,7 @@ import Strings from '../../../codebases/compdem/client-participation/js/strings/
import { getMath, getComments } from '../../../.storybook/utils'
const mathResults = getMath()
-const commentsData = getComments()
-commentsData.sort((a,b) => a.tid - b.tid)
+const commentsData = getComments().sort((a, b) => a.tid - b.tid)
const pluckNBetweenLowerUpper = (n, lower, upper) => {
let numbers = []
@@ -19,18 +18,12 @@ const pluckNBetweenLowerUpper = (n, lower, upper) => {
}
// Ascending integer sort.
numbers.sort((a, b) => a - b)
-
+
return numbers
}
export default {
component: TidCarousel,
- argTypes: {
- selectedTidCuration: {
- options: [null, "majority", 0, 1, 2, 3],
- control: { type: 'inline-radio' },
- },
- },
}
const Template = (args) => {
@@ -54,7 +47,11 @@ const Template = (args) => {
?.map(i => i.tid).includes(c.tid)
)
- return
+ return
}
export const Interactive = Template.bind({})
@@ -62,10 +59,16 @@ Interactive.args = {
selectedTidCuration: 0,
Strings,
}
+Interactive.argTypes = {
+ selectedTidCuration: {
+ options: [null, "majority", 0, 1, 2, 3],
+ control: { type: 'inline-radio' },
+ },
+}
export const Default = Template.bind({})
Default.args = {
- selectedTidCuration: 1,
+ selectedTidCuration: undefined,
commentsToShow: commentsData.slice(10,20),
selectedComment: null,
// TODO: Pretty sure this is janky. It should be simply action("Clicked")
@@ -77,6 +80,51 @@ Default.args = {
Strings,
}
+export const Empty = Template.bind({})
+Empty.args = {
+ commentsToShow: [],
+ selectedTidCuration: globals.tidCuration.majority,
+ selectedComment: null,
+ // TODO: Pretty sure this is janky. It should be simply action("Clicked")
+ // and the prop in tidCarousel should be:
+ // onClick={() => this.props.handleCommentClick(c)}
+ // not just
+ // onClick={this.props.handleCommentClick(c)}
+ handleCommentClick: (c) => () => action("Clicked")(c),
+ Strings,
+}
+
+export const OneStatement = Template.bind({})
+OneStatement.args = {
+ ...Empty.args,
+ commentsToShow: pluckNBetweenLowerUpper(1, 0, 25).map(i => ({ tid: i })),
+}
+
+export const FiveStatements = Template.bind({})
+FiveStatements.args = {
+ ...Empty.args,
+ commentsToShow: pluckNBetweenLowerUpper(5, 0, 25).map(i => ({ tid: i })),
+}
+
+export const SixStatements = Template.bind({})
+SixStatements.args = {
+ ...Empty.args,
+ commentsToShow: pluckNBetweenLowerUpper(6, 0, 25).map(i => ({ tid: i })),
+}
+
+export const TenStatements = Template.bind({})
+TenStatements.args = {
+ ...Empty.args,
+ commentsToShow: pluckNBetweenLowerUpper(10, 0, 25).map(i => ({ tid: i })),
+}
+
+export const Selected = Template.bind({})
+Selected.args = {
+ ...Empty.args,
+ commentsToShow: commentsData.slice(10,20),
+ selectedComment: commentsData[11],
+}
+
// TODO: Load dataset with hundreds/thousands of comments.
//export const DoubleToTripleDigits = Template.bind({})
//DoubleToTripleDigits.args = {
@@ -84,32 +132,24 @@ Default.args = {
// commentsToShow: commentsData.slice(95,105),
//}
-export const StatementSelected = Template.bind({})
-StatementSelected.args = {
- ...Default.args,
- selectedComment: { tid: commentsData[11].tid }
-}
+// export const Pagination = Template.bind({})
+// Pagination.args = {
+// ...Default.args,
+// commentsToShow: commentsData.slice(10,40),
+// }
-export const FewStatements = Template.bind({})
-FewStatements.args = {
+export const UpToDoubleDigits = Template.bind({})
+UpToDoubleDigits.args = {
...Default.args,
- commentsToShow: commentsData.slice(10,15),
+ commentsToShow: pluckNBetweenLowerUpper(10, 0, 100).map(i => ({ tid: i })),
}
-export const Pagination = Template.bind({})
-Pagination.args = {
+export const UpToTripleDigits = Template.bind({})
+UpToTripleDigits.args = {
...Default.args,
- commentsToShow: commentsData.slice(10,40),
+ commentsToShow: pluckNBetweenLowerUpper(10, 0, 400).map(i => ({ tid: i })),
}
-export const UpToDoubleDigits = Template.bind({})
-UpToDoubleDigits.args = {
- ...Default.args,
- commentsToShow: [
- ...pluckNBetweenLowerUpper(10, 0, commentsData.length-1).map(i => commentsData[i])
- ]
-}
-
export const NoGroupSelectedSoHidden = Template.bind({})
NoGroupSelectedSoHidden.args = {
...Default.args,