Open scottnath opened 5 years ago
This is the set of requirements we put together to track the various pieces of a component. It needs to be updated because there are many many more files and more data associated with a component imho - but this is a good start for the basics of what's required
Feature: Cross-team and cross-technology pattern
As a developer
I want to document how we will store and distribute my team's patterns
So that my team can document, store, and build upon my team's efforts
Scenario: Module exports an object
Given that I have a pattern for use in multiple projects and scenarios
And that my pattern will be distributed as an npm module
And that my pattern must include a content model
And that my pattern may be designed in Sketch
And that my pattern may be designed in Adobe Illustrator
And that my pattern may be built using nunjucks templating
And that my pattern may be built as a React component
And that my pattern may be built as an Angular 1x component
And that my pattern may be built as an Angular 2x component
And that my pattern may include a style sheet
When I release my pattern for use
Then it should be released as an npm module
And said module should export an object
And said object may have a key who's value represents the Sketch file
And said object may have a key who's value represents the AI file
And said object must have a key who's value represents the canonical version
And said object may have a key who's value represents the nunjucks version
And said object may have a key who's value represents the React version
And said object may have a key who's value represents the Angular 1x version
And said object may have a key who's value represents the Angular 2x version
And said object should have a key who's value represents the content model
And said object should have a key who's value is a function which returns an object of content
And said content object should return example content
And said content object should be addressable by key
And said content function should accept parameters to vary what is returned.
Scenario: Pattern has dependencies
Given that I have an interface that my healthcare ux pattern that includes a form
And that my app is built using components
And that portions of the form may be built from components in an external component library
When my app imports my healthcare pattern
Then it should import the external library as a dependency
and my app should have access to all styles required by my pattern.
Scenario: Pattern is connected to a clearly defined User Story
Given that I have a pattern for use in multiple projects and scenarios
And that my pattern should have been created according to one or more user stories
And that said stories must be written for a specific user
And that said users should be one of our pre-determined personas
When I am creating documentation on my pattern's creation
And said pattern should be distributed with documentation
And said documentation should include all relevant user stories
And said documentation should include references to represented personas
And said documentation may be in the module's README.
Scenario: Canonical Design
Given that I need a source-of-truth to represent my pattern's design
And that said source should include example content
And that said source should have UX to match the user story
And that said source should have a design that follows Watson Health guidelines
And that said guidelines can be enforced using Sketch libraries
When I want an design representing the new feature as described in the user story
Then I need my design to be created in Sketch
And said design will be represented by a single Sketch file
And said Sketch file should include all libraries which enforce Watson Health guidelines
And said Sketch file should accept content
And said content should match the story's content model
And said design should represent all of the story's UX requirements
And said design should conform to Watson Health guidelines
And said design should represent all content variations.
Scenario: Canonical Implementation
Given that I need a source-of-truth to represent my pattern's implementation
And that said source should include example content
And that said source should be styled to match the design
When I want an example representing my pattern
Then I need my example to be written in semantic HTML
And said HTML should contain all elements required by my pattern
And said elements should contain all attributes required by my pattern
And said pattern should accept content
And said content should conditionally change the viewed pattern
And said example should be tested to match the user story requirements.
Scenario: Pattern is implementation agnostic
Given that I have a pattern for use in multiple projects and scenarios
And that said projects may be implemented using disparate technology solutions
And that said solutions should create consistent HTML markup
And that said solutions should follow a consistent element class naming structure
When I am creating an implementation-specific version of my pattern
Then my new version should have the same markup as the canonical version
And said version should accept content
And said content should conditionally change the viewed pattern
And said version should match the canonical when viewed by a user
And said version should match the canonical when unit-tested
And said version should be tested to match the user story requirements.
Scenario: Pattern should match external versions
Given that my pattern may be implemented by external repositories
And that external implementations should produce the same HTML as my canonical version
When testing my pattern
Then my tests should include the external implementation
And the external version should be run through the default unit tests for my implementation
And there should be a way to determine inconsistencies between implementations.
Scenario: Anatomy of a pattern
Given that I have a pattern for use in multiple projects and scenarios
When I am creating a home for my pattern
Then that pattern should be use-able via multiple technologies
And said pattern should be distributed with a README
And said README should include usage instructions
And said pattern's module should include documentation
And said pattern's module should export an object
And said pattern's module should include a canonical design
And said pattern's module should include a canonical implementation
And said pattern's module may include multiple implementations
And said module's patterns should be tested against external pattern implementations
And said multiple implementations must pass the same tests as the canonical version.
Cross-team and cross-technology pattern
Items specific to the carbon-spec
repo:
generate
)generate
functionIn a carbon-components-X
repo
carbon-spec
on various demos to verify implementationMain pain point: in this current setup the only way to verify the exportable tests is by working in parallel with a carbon-component-X
repo since the template and demos are defined there. I feel like we wouldn't want static HTML as the carbon-specs
repo since there are many demos you'd want to test for thoroughness of variants, states, modifiers, etc so I'm not sure if there is away around this.
There should be a canonical set of demos (variants). For instance, button has multiple types
as listed by Carbon's next site:
https://next.carbondesignsystem.com/components/button/usage
They are:
If all of these items are something a developer should expect to be available in their framework of choice, then there should be a configuration that breaks down each variant the should be part of a given component's spec. These would also be reflected within the selectors object.
Point being...under In a carbon-components-X repo
section, this line:
configuration file that sets up demos/documentation specific the framework
should prol be:
configuration file that sets up additional demos/documentation specific the framework
and Items specific to the carbon-spec repo:
should have a bullet-point that clearly denotes it is the source for all variants that each framework should expect to have developed. These would also be reflected via the tests the spec repo contains as well as the variant selectors available via the selectors object.
This line: contains a function that can take a configuration object and output a template context object (generate)
is framework specific. Each framework configures their template/module/component/meow differently, but we could share the pre-generate configuration object across frameworks. So, before we generate out handlebars-specific template configuration, we have some a set of parameters which are more generic:
{
variant: 'danger',
icon: 'information',
content: 'Danger button'
}
in our generate
function that produces configuration that will create a button in the danger
variant styles that has an information
icon with the content of the button being Danger button
. It would make sense if each framework shared a similar api. That theory would mean that the React version which now accepts this:
<Button kind="danger" {...setProps}>
Danger button
</Button>
could align by accepting this:
<Button variant="danger" icon="information">
Danger button
</Button>
or conversely, the Handlebars version could align by exchanging variant
with kind
.
Both of the above get us closer to a canonical set of variants (kinds? demos?). So your pain point
of " in this current setup the only way to verify the exportable tests is by working in parallel with a carbon-component-X repo since the template and demos are defined there." can be fixed if carbon-specs contains the demos.
This also means that if carbon-components-meow has a new button variant, and that variant is something approved for global use across the carbon frameworks by being accepted by IBM design...then it could be moved to carbon-specs
as a voluntary feature, that can be tested for, but maybe not fail anyone's compliance until it's deemed a required
feature.
@scottnath here is my updated list. My only concern is the template in the spec repo...
carbon-spec
repo:generate
functionscarbon-components-X
repogenerate
)generate
functioncarbon-spec
on various demos to verify implementationJust a heads up @scottnath, in this example for the React API:
<Button variant="danger" icon="information">
We actually have to move away from the icon name API as it's a pattern that isn't easily tree-shaken 😞 In order to implement, we have to do a pattern like:
import AllIcons from 'icons-package';
export default function MyComponent({ icon }) {
return (
<>
<p>Some text</p>
{AllIcons[icon]}
</>
);
}
Which means that we have a runtime lookup 😞
Just catching up here, but one thing I've been thinking about is if spec should export anything, or if it should be an aggregator.
One hope of mine with this project would be to support a view like: https://test262.report/ where, instead of engines, we should framework implementations and their corresponding coverage. The way we could report on frameworks is by having them PR into spec. A structure could be:
carbon-components-react
The project itself would be responsible for three assets:
reports
directory@joshblack I'm following the idea you have of it containing the reports for the each implementation/framework and I think the report like test262 is a very interesting idea. I do think that the spec repo would be a bit more though than just these reports. To my understanding this repo was meant to be the location of all things that are common despite what JS framework is being used. I'm also a little curious as to what the work flow would be for this to make sure that what's in spec and what's in the framework specific repo are always in sync.
As far as the spec document goes I think we need to do something different than the aria site. It's not clear what "user needs" are, expected behavior, etc and in general it's a bit daunting. During my a11y meetings the one consistent thing that people talk about is how the standards documentation is not clear. I think there are aspects of what they are doing that would could certainly pull in but that we will want to re-think the structure and content that is actually included.
@joshblack I don't see why we couldn't have top-level spec
(consumed by carbon-components-x for implementation), test
(consumed by carbon-components-x for spec verification), and reports
(for carbon-components-x to PR to) as top-level directories. Unless that third part gets too noisy, and we need something separate to track spec adherence.
Side note: maybe the spec adherence reporting would better live in a separate repo where we track other design system KPIs for adoption and contributions. Framework spec coverage will depend on strong contributions after all.
@scottnath @elizabethsjudd I move discussion on generate functions to #8. Looking forward to hearing your thoughts.
@elizabethsjudd this goes to your questions about how we create the static HTML. These should not be files written by a human. Ideally, these files would be autogenerated from a framework. It seems though, that this is not really something that would be only coming from one framework:
Steps to change canonical HTML:
button
component, adding some meow attribute, which fixes the bugButton
angular module and compares their static HTML output to the canonical set of HTML files in carbon-specbutton
spec is merged (after extensive and thorough review)points being:
Luckily all the frameworks use javascript, so it can be an ingestible object. This would require some level common API between the systems though. Sounds like that might be tricky in the short term though, so this may fall on the tests.
secondary
button test that tests HTML of a secondary buttonbx--btn bx--btn--secondary
, attributes=(only non-framework specific attributes are checked, all others ignored)reports
directoryDo we need these reports to be files? Can the reports all be within a framework's CI process? Output could be created and visible via site on github-pages or carbon..com perhaps.
Regardless...we would expect regular changes to be happening across all frameworks and if there is a process of PRs for merging new report files, that could make the reporting lag behind the actual code in the frameworks. Live snapshots could reduce this delay.
For clarification, we should define:
"configuration object": refers to a non-framework specific configuration object that would be ingested by a framework and used to create the output.
So... @joshblack to your point about a runtime issue in React in finding the right icon - my React example was made without deep knowledge of React. The real goal is that for someone using carbon-components-react to create an app who wanted to create a button could use the configuration equaling:
{
variant: 'danger',
icon: 'information',
content: 'Danger button'
}
to create a React-created danger button with the info icon and Danger button
for the content.
So when we say the frameworks should share an input api - that api at the component level can be referred to as a "component's configuration object".
@joshblack @scottnath @mattrosno See this https://github.com/carbon-design-system/carbon-spec/issues/8#issuecomment-458642152 for more around Scott's comment on configuration object vs template/framework config object
To my understanding this repo was meant to be the location of all things that are common despite what JS framework is being used.
@elizabethsjudd I think something that would be valuable is to decouple implementation details from the spec. It would be great if we could have it so that anyone could implement the spec, but we have a canonical implementation that follows it if you don't want to do it custom. Decoupling things in this way could mean that we could have potentially multiple implementations that could work in various contexts that still adhere to the spec. One example could be around styles, where one style implementation would want to leverage sass while another one wants to leverage a CSS-in-JS solution.
@mattrosno Would 100% make sense to export the runner if implementations wanted to use it in their own projects 👍 Could easily see new framework XYZ wanting to follow TDD with:
/* Test file */
// Proposed API
import { runner, runComponent } from '@carbon/spec';
describe('ComponentName', () => {
test('spec', () => {
// Run specific component check
runComponent('ComponentName', /* mount fn */);
});
});
And working interactively to make sure it hits all the necessary rulesets.
@joshblack all the conversations we've had to this point were that Sass was also going to live in this repo. Breaking out Sass to allow something like you're describing does make sense in flexibility, it's just new to these conversations and we'd want to figure out where Sass would live than.
I think in terms of workflow it'd be great if we could keep the styles colocated with a canonical implementation versus in the spec, mostly because it can be easier to create component permutations and debug interactive styles when combined with a framework or environment like fractal.
Things like exporting selectors then can be tied to the style implementation versus the spec. This could be valuable if, once again, teams want to drive forward with an alternative style implementation that still adheres to the spec. This could help if things like selectors mean different things to a framework using sass versus something using CSS-in-JS.
As we get deeper into the proof of concept, I hope this will be more clear. Should (1) the spec be used just for component requirements, exported test runner and test reporting purposes? Or (2) should the spec also provide configuration objects (element
, attributes
, classNames
, content
) when carbon-components-x asks for them.
I'll continue to push on (2) in the proof of concept.
Is your feature request related to a problem? Please describe. Component directory structure should be architected in such a way that the content of a component, be it files or data, is consistently written and structured and available for straightforward external usage.
Describe the solution you'd like Documentation which we can refer to which says what files would be where. ie: sass, written requirements, requirements-tests would be in
spec
, handlebars templates in carbon-components, react versions in carbon-c-react, etc.Also...regardless of the location, there should be an easy way to import these files and component-data from a single location. So, if I pulled in carbon-spec/src/accordion I could find that files like user-requirements.feature, index.scss (instead of _accordion.scss), _mixins.scss (etc) within that directory. There could also be a node file, index.js, which would output data required by the component - for instance content models, objects describing each variant or scenario, etc.
I'll add a comment below which contains the
gherkin
we used when architecting our component directories.Describe alternatives you've considered n/a
Acceptance Criteria