diff --git a/.gitignore b/.gitignore index 161c306e8d..ca29ecad92 100644 --- a/.gitignore +++ b/.gitignore @@ -7,14 +7,10 @@ coverage/ dist/ -docs/src/componentInfo -docs/src/componentMenu.json -docs/src/behaviorMenu.json docs/src/currentBundleStats.json -docs/src/exampleMenus -docs/src/exampleSources docs/dist/ node_modules/ report.*.json stats/ .vscode/ +.netlify diff --git a/build/gulp/plugins/gulp-component-menu-behaviors.ts b/build/gulp/plugins/gulp-component-menu-behaviors.ts deleted file mode 100644 index 893d3f20db..0000000000 --- a/build/gulp/plugins/gulp-component-menu-behaviors.ts +++ /dev/null @@ -1,101 +0,0 @@ -import gutil from 'gulp-util' -import path from 'path' -import through2 from 'through2' -import Vinyl from 'vinyl' -import _ from 'lodash' -import fs from 'fs' - -const pluginName = 'gulp-component-menu-behaviors' -const extract = require('extract-comments') -const doctrine = require('doctrine') - -type BehaviorMenuItem = { - displayName: string - type: string - variations: { - name: string - description: string - specification: string - } -} - -const getTextFromCommentToken = (commentTokens, tokenTitle): string => { - const resultToken = commentTokens.find(token => token.title === tokenTitle) - return resultToken ? resultToken.description : '' -} - -export default () => { - const result: BehaviorMenuItem[] = [] - function bufferContents(file, enc, cb) { - if (file.isNull()) { - cb(null, file) - return - } - - if (file.isStream()) { - cb(new gutil.PluginError(pluginName, 'Streaming is not supported')) - return - } - - try { - const absPath = path.resolve(process.cwd(), file.path) - const dir = path.dirname(absPath) - const componentType = _.lowerFirst(path.basename(path.dirname(dir)).replace(/s$/, '')) - const behaviorVariantName = file.basename - const behaviorName = path.basename(dir) - const fileContent = fs.readFileSync(file.path).toString() - const blockComments = extract(fileContent).filter(comment => comment.type === 'BlockComment') // filtering only block comments - const variation = { - name: behaviorVariantName, - description: '', - specification: '', - } - - // getting description and specification of the comment's text - if (!_.isEmpty(blockComments)) { - const commentTokens = doctrine.parse(blockComments[0].raw, { unwrap: true }).tags - variation.description = getTextFromCommentToken(commentTokens, 'description') - variation.specification = getTextFromCommentToken(commentTokens, 'specification') - } - - result.push({ - displayName: behaviorName, - type: componentType, - variations: variation, - }) - cb() - } catch (err) { - const pluginError = new gutil.PluginError(pluginName, err) - const relativePath = path.relative(process.cwd(), file.path) - pluginError.message = [ - gutil.colors.magenta(`Error in file: ${relativePath}`), - gutil.colors.red(err.message), - gutil.colors.gray(err.stack), - ].join('\n\n') - this.emit('error', pluginError) - } - } - - function getParsedResults() { - return _.chain(result) - .groupBy('displayName') - .map((behaviors, displayName) => ({ - displayName, - type: behaviors[0].type, - variations: _.map(behaviors, 'variations'), - })) - .value() - } - - function endStream(cb) { - const file = new Vinyl({ - path: './behaviorMenu.json', - contents: Buffer.from(JSON.stringify(getParsedResults(), null, 2)), - }) - - this.push(file) - cb() - } - - return through2.obj(bufferContents, endStream) -} diff --git a/build/gulp/plugins/gulp-component-menu.ts b/build/gulp/plugins/gulp-component-menu.ts deleted file mode 100644 index 2e7dfbf359..0000000000 --- a/build/gulp/plugins/gulp-component-menu.ts +++ /dev/null @@ -1,76 +0,0 @@ -import gutil from 'gulp-util' -import _ from 'lodash' -import fs from 'fs' -import path from 'path' -import through2 from 'through2' -import Vinyl from 'vinyl' - -import config from '../../../config' -import getComponentInfo from './util/getComponentInfo' - -const pluginName = 'gulp-component-menu' - -type ComponentMenuItem = { - displayName: string - type: string -} - -export default () => { - const result: ComponentMenuItem[] = [] - - function bufferContents(file, enc, cb) { - if (file.isNull()) { - cb(null, file) - return - } - - if (file.isStream()) { - cb(new gutil.PluginError(pluginName, 'Streaming is not supported')) - return - } - - try { - const infoFilename = file.basename.replace(/\.tsx$/, '.info.json') - const infoFilePath = config.paths.docsSrc('componentInfo', infoFilename) - - let componentInfo - - // We will reuse an info file if it exists. - if (fs.existsSync(infoFilePath)) { - const jsonInfo = fs.readFileSync(infoFilePath) - componentInfo = JSON.parse(jsonInfo.toString()) - } else { - componentInfo = getComponentInfo(file.path, []) - } - - if (componentInfo.isParent) { - result.push({ - displayName: componentInfo.displayName, - type: componentInfo.type, - }) - } - cb() - } catch (err) { - const pluginError = new gutil.PluginError(pluginName, err) - const relativePath = path.relative(process.cwd(), file.path) - pluginError.message = [ - gutil.colors.magenta(`Error in file: ${relativePath}`), - gutil.colors.red(err.message), - gutil.colors.gray(err.stack), - ].join('\n\n') - this.emit('error', pluginError) - } - } - - function endStream(cb) { - const file = new Vinyl({ - path: './componentMenu.json', - contents: Buffer.from(JSON.stringify(_.sortBy(result, 'displayName'), null, 2)), - }) - - this.push(file) - cb() - } - - return through2.obj(bufferContents, endStream) -} diff --git a/build/gulp/plugins/gulp-doctoc.ts b/build/gulp/plugins/gulp-doctoc.ts deleted file mode 100644 index 71ee1d22a0..0000000000 --- a/build/gulp/plugins/gulp-doctoc.ts +++ /dev/null @@ -1,17 +0,0 @@ -import fs from 'fs' -import through2 from 'through2' - -import config from '../../../config' -import sh from '../sh' - -const insideGitRepo = fs.existsSync(config.paths.base('.git')) - -export default () => - through2.obj((file, enc, done) => { - sh(`doctoc ${file.path} --github --maxlevel 4`) - .then(() => insideGitRepo && sh(`git add ${file.path}`)) - .then(() => { - done(null, file) - }) - .catch(done) - }) diff --git a/build/gulp/plugins/gulp-example-menu.ts b/build/gulp/plugins/gulp-example-menu.ts deleted file mode 100644 index 20b5f0ebdb..0000000000 --- a/build/gulp/plugins/gulp-example-menu.ts +++ /dev/null @@ -1,94 +0,0 @@ -import gutil from 'gulp-util' -import _ from 'lodash' -import path from 'path' -import through2 from 'through2' -import Vinyl from 'vinyl' - -import { parseDocSection } from './util' -import { ObjectOf } from 'packages/react/src/types' - -const SECTION_ORDER = { - Types: 1, - States: 2, - Content: 3, - Variations: 4, - Groups: 5, - DEFAULT_ORDER: 6, - Usage: 9, - Rtl: 10, - Performance: 11, -} - -const getSectionOrder = sectionName => - _.find(SECTION_ORDER, (val, key) => _.includes(sectionName, key)) || SECTION_ORDER.DEFAULT_ORDER - -const pluginName = 'gulp-example-menu' - -export default () => { - const exampleFilesByDisplayName: ObjectOf< - ObjectOf<{ - sectionName: string - examples: ObjectOf - order: number - }> - > = {} - - function bufferContents(file, enc, cb) { - if (file.isNull()) { - cb(null, file) - return - } - - if (file.isStream()) { - cb(new gutil.PluginError(pluginName, 'Streaming is not supported')) - return - } - - try { - const pathParts = _.split(file.path, path.sep).slice(-4) - const displayName = pathParts[1] - const sectionName = pathParts[2] - const { examples } = parseDocSection(file.contents) - - _.merge(exampleFilesByDisplayName, { - [displayName]: { - [sectionName]: { - sectionName, - examples, - order: getSectionOrder(sectionName), - }, - }, - }) - - cb() - } catch (err) { - const pluginError = new gutil.PluginError(pluginName, err) - const relativePath = path.relative(process.cwd(), file.path) - pluginError.message = [ - gutil.colors.magenta(`Error in file: ${relativePath}`), - gutil.colors.red(err.message), - gutil.colors.gray(err.stack), - ].join('\n\n') - this.emit('error', pluginError) - } - } - - function endStream(cb) { - _.forEach(exampleFilesByDisplayName, (contents, displayName) => { - const sortedContents = _.sortBy(contents, ['order', 'sectionName']).map( - ({ sectionName, examples }) => ({ sectionName, examples }), - ) - - const file = new Vinyl({ - path: `./${displayName}.examples.json`, - contents: Buffer.from(JSON.stringify(sortedContents, null, 2)), - }) - - this.push(file) - }) - - cb() - } - - return through2.obj(bufferContents, endStream) -} diff --git a/build/gulp/plugins/gulp-example-source.ts b/build/gulp/plugins/gulp-example-source.ts deleted file mode 100644 index 9826d42f37..0000000000 --- a/build/gulp/plugins/gulp-example-source.ts +++ /dev/null @@ -1,71 +0,0 @@ -import * as Babel from '@babel/core' -import { CLIEngine } from 'eslint' -import gutil from 'gulp-util' -import prettier from 'prettier' -import through from 'through2' -import Vinyl from 'vinyl' - -const prettierConfig = require('../../../.prettierrc.json') - -import { ExampleSource } from '../../../docs/src/types' -import transformStarImportPlugin from '../../babel/transform-star-import-plugin' -import { getRelativePathToSourceFile } from './util' - -const ESLint = new CLIEngine({ - fix: true, -}) -const pluginName = 'gulp-example-source' - -const createExampleSourceCode = (file: Vinyl): ExampleSource => { - const tsSource = file.contents.toString() - - const babelResult = Babel.transform(tsSource, { - // This plugin transforms TS files for docs, we want to apply exactly this config. - configFile: false, - plugins: [transformStarImportPlugin], - presets: [['@babel/preset-typescript', { allExtensions: true, isTSX: true }]], - sourceType: 'module', - }) - const prettierResult = prettier.format(babelResult.code, { - ...prettierConfig, - parser: 'babel', - }) - // https://eslint.org/docs/developer-guide/nodejs-api#cliengineexecuteontext - // Results will contain single entry - const eslintResult = ESLint.executeOnText(prettierResult, file.path).results[0] - - return { - // result.output is omitted if no fix is available - js: eslintResult.output || prettierResult, - ts: tsSource, - } -} - -export default () => - through.obj((file: Vinyl, enc, cb) => { - if (file.isNull()) { - cb(null, file) - return - } - - if (file.isStream()) { - cb(new gutil.PluginError(pluginName, 'Streaming is not supported')) - return - } - - try { - const sourcePath = getRelativePathToSourceFile(file.path) - const source = createExampleSourceCode(file) - - const sourceFile = new Vinyl({ - path: sourcePath, - contents: Buffer.from(JSON.stringify(source, null, 2)), - }) - // `gulp-cache` relies on this private entry - sourceFile._cachedKey = file._cachedKey - - cb(null, sourceFile) - } catch (e) { - cb(e) - } - }) diff --git a/build/gulp/serve.ts b/build/gulp/serve.ts index e570f34232..21e00c1357 100644 --- a/build/gulp/serve.ts +++ b/build/gulp/serve.ts @@ -1,4 +1,4 @@ -import express from 'express' +import * as express from 'express' import historyApiFallback from 'connect-history-api-fallback' import { Server } from 'http' diff --git a/build/gulp/tasks/docs.ts b/build/gulp/tasks/docs.ts index 28dfa42c75..d86bbe6593 100644 --- a/build/gulp/tasks/docs.ts +++ b/build/gulp/tasks/docs.ts @@ -1,282 +1,16 @@ -import { dest, lastRun, parallel, series, src, task, watch } from 'gulp' -import chalk from 'chalk' -import cache from 'gulp-cache' -import remember from 'gulp-remember' -import fs from 'fs' -import path from 'path' -import rimraf from 'rimraf' -import through2 from 'through2' -import webpack from 'webpack' -import WebpackDevMiddleware from 'webpack-dev-middleware' -import WebpackHotMiddleware from 'webpack-hot-middleware' +import * as cp from 'child_process' +import * as path from 'path' +import { task } from 'gulp' -import sh from '../sh' -import config from '../../../config' -import gulpComponentMenu from '../plugins/gulp-component-menu' -import gulpComponentMenuBehaviors from '../plugins/gulp-component-menu-behaviors' -import gulpDoctoc from '../plugins/gulp-doctoc' -import gulpExampleMenu from '../plugins/gulp-example-menu' -import gulpExampleSource from '../plugins/gulp-example-source' -import gulpReactDocgen from '../plugins/gulp-react-docgen' -import { getRelativePathToSourceFile } from '../plugins/util' -import webpackPlugin from '../plugins/gulp-webpack' -import { Server } from 'http' -import serve, { forceClose } from '../serve' +const DOCS_ROOT = path.resolve(__dirname, '../../../docs-v2') -const { paths } = config -const g = require('gulp-load-plugins')() - -const { log } = g.util - -const logWatchAdd = filePath => log('Created', chalk.blue(path.basename(filePath))) -const logWatchChange = filePath => log('Changed', chalk.magenta(path.basename(filePath))) -const logWatchUnlink = filePath => log('Deleted', chalk.red(path.basename(filePath))) - -const handleWatchUnlink = (group, filePath) => { - logWatchUnlink(filePath) - remember.forget(group, filePath) -} - -// ---------------------------------------- -// Clean -// ---------------------------------------- - -task('clean:cache', () => cache.clearAll()) - -task('clean:docs:schema', cb => { - rimraf(paths.packages('ability-attributes', 'src/schema.ts'), cb) -}) - -task('clean:docs:component-menu', cb => { - rimraf(paths.docsSrc('componentMenu.json'), cb) -}) - -task('clean:docs:component-menu-behaviors', cb => { - rimraf(paths.docsSrc('behaviorMenu.json'), cb) -}) - -task('clean:docs:dist', cb => { - rimraf(paths.docsDist(), cb) -}) - -task('clean:docs:example-menus', cb => { - rimraf(paths.docsSrc('exampleMenus'), cb) -}) - -task('clean:docs:example-sources', cb => { - rimraf(paths.docsSrc('exampleSources'), cb) -}) - -task( - 'clean:docs', - parallel( - 'clean:docs:component-menu', - 'clean:docs:component-menu-behaviors', - 'clean:docs:dist', - 'clean:docs:schema', - 'clean:docs:example-menus', - 'clean:docs:example-sources', - ), -) - -// ---------------------------------------- -// Build -// ---------------------------------------- - -const componentsSrc = [ - `${paths.posix.packageSrc('react')}/components/*/[A-Z]*.tsx`, - `${paths.posix.packageSrc('react-component-ref')}/[A-Z]*.tsx`, - `${paths.posix.packageSrc('react')}/lib/accessibility/FocusZone/[A-Z]!(*.types).tsx`, -] -const behaviorSrc = [`${paths.posix.packageSrc('accessibility')}/behaviors/*/[a-z]*Behavior.ts`] -const examplesIndexSrc = `${paths.posix.docsSrc()}/examples/*/*/*/index.tsx` -const examplesSrc = `${paths.posix.docsSrc()}/examples/*/*/*/!(*index|.knobs).tsx` -const markdownSrc = [ - '.github/CONTRIBUTING.md', - '.github/setup-local-development.md', - '.github/add-a-feature.md', - '.github/document-a-feature.md', - '.github/test-a-feature.md', - 'specifications/*.md', -] -const schemaSrc = `${paths.posix.packages('ability-attributes')}/schema.json` - -task('build:docs:component-info', () => - src(componentsSrc, { since: lastRun('build:docs:component-info') }) - .pipe(cache(gulpReactDocgen(['DOMAttributes', 'HTMLAttributes']), { name: 'componentInfo-1' })) - .pipe(dest(paths.docsSrc('componentInfo'))), -) - -task('build:docs:component-menu', () => - src(componentsSrc, { since: lastRun('build:docs:component-menu') }) - .pipe(gulpComponentMenu()) - .pipe(dest(paths.docsSrc())), -) - -task('build:docs:component-menu-behaviors', () => - src(behaviorSrc, { since: lastRun('build:docs:component-menu-behaviors') }) - .pipe(remember('component-menu-behaviors')) - .pipe(gulpComponentMenuBehaviors()) - .pipe(dest(paths.docsSrc())), -) - -task('build:docs:example-menu', () => - src(examplesIndexSrc, { since: lastRun('build:docs:example-menu') }) - .pipe(remember('example-menu')) // FIXME: with watch this unnecessarily processes index files for all examples - .pipe(gulpExampleMenu()) - .pipe(dest(paths.docsSrc('exampleMenus'))), -) - -task('build:docs:example-sources', () => - src(examplesSrc, { since: lastRun('build:docs:example-sources') }) - .pipe( - cache(gulpExampleSource(), { - name: 'exampleSources', - }), - ) - .pipe(dest(paths.docsSrc('exampleSources'))), -) - -task( - 'build:docs:json', - parallel( - series('build:docs:component-info', 'build:docs:component-menu'), - 'build:docs:component-menu-behaviors', - 'build:docs:example-menu', - 'build:docs:example-sources', - ), -) - -task('build:docs:html', () => src(paths.docsSrc('404.html')).pipe(dest(paths.docsDist()))) - -task('build:docs:images', () => - src(`${paths.docsSrc()}/**/*.{png,jpg,gif}`).pipe(dest(paths.docsDist())), -) - -task('build:docs:toc', () => - src(markdownSrc, { since: lastRun('build:docs:toc') }).pipe( - cache(gulpDoctoc(), { - name: 'md-docs', - }), - ), -) - -task('build:docs:schema', () => - src(schemaSrc, { since: lastRun('build:docs:schema') }).pipe( - through2.obj((file, enc, done) => { - sh(`cd packages/ability-attributes && npm run schema`) - .then(() => done(null, file)) - .catch(done) - }), - ), -) - -task('build:docs:webpack', cb => { - webpackPlugin(require('../../webpack.config').default, cb) -}) - -task( - 'build:docs:assets', - parallel( - 'build:docs:toc', - 'build:docs:schema', - series('clean:docs', parallel('build:docs:json', 'build:docs:html', 'build:docs:images')), - ), -) - -task('build:docs', series('build:docs:assets', 'build:docs:webpack')) - -// ---------------------------------------- -// Deploy -// ---------------------------------------- - -task('deploy:docs', cb => { - const relativePath = path.relative(process.cwd(), paths.docsDist()) - return sh(`gh-pages -d ${relativePath} -m "deploy docs [ci skip]"`) -}) - -// ---------------------------------------- -// Serve -// ---------------------------------------- - -let server: Server - -task('serve:docs', async () => { - server = await serve(paths.docsDist(), config.server_host, config.server_port) -}) - -task('serve:docs:hot', async () => { - const webpackConfig = require('../../webpack.config').default - const compiler = webpack(webpackConfig) - - server = await serve(paths.docsDist(), config.server_host, config.server_port, app => - app - .use( - WebpackDevMiddleware(compiler, { - publicPath: webpackConfig.output.publicPath, - contentBase: paths.docsSrc(), - hot: true, - quiet: false, - noInfo: true, // must be quite for hot middleware to show overlay - lazy: false, - stats: config.compiler_stats, - }), - ) - .use(WebpackHotMiddleware(compiler)), - ) +task('build:docs', cb => { + cp.execSync('yarn build', { cwd: DOCS_ROOT }) + cb() }) -task('serve:docs:stop', () => forceClose(server)) - -// ---------------------------------------- -// Watch -// ---------------------------------------- - -task('watch:docs', cb => { - // rebuild component info - watch(componentsSrc, series('build:docs:component-info')) - .on('add', logWatchAdd) - .on('change', logWatchChange) - .on('unlink', logWatchUnlink) - - watch(schemaSrc, series('build:docs:schema')).on('change', logWatchChange) - - // rebuild example menus - watch(examplesIndexSrc, series('build:docs:example-menu')) - .on('add', logWatchAdd) - .on('change', logWatchChange) - .on('unlink', filePath => handleWatchUnlink('example-menu', filePath)) - - watch(examplesSrc, series('build:docs:example-sources')) - .on('add', logWatchAdd) - .on('change', logWatchChange) - .on('unlink', filePath => { - logWatchUnlink(filePath) - - const sourceFilename = getRelativePathToSourceFile(filePath) - const sourcePath = config.paths.docsSrc('exampleSources', sourceFilename) - - try { - fs.unlinkSync(sourcePath) - } catch (e) {} - }) - - watch(behaviorSrc, series('build:docs:component-menu-behaviors')) - .on('add', logWatchAdd) - .on('change', logWatchChange) - .on('unlink', filePath => handleWatchUnlink('component-menu-behaviors', filePath)) - - // rebuild images - watch(`${config.paths.docsSrc()}/**/*.{png,jpg,gif}`, series('build:docs:images')) - .on('add', logWatchAdd) - .on('change', logWatchChange) - .on('unlink', logWatchUnlink) - +// TODO: wait for docs to be running before invoking cb +task('serve:docs', cb => { + cp.spawn('yarn', ['start'], { cwd: DOCS_ROOT, stdio: 'inherit' }) cb() }) - -// ---------------------------------------- -// Default -// ---------------------------------------- - -task('docs', series('build:docs:assets', 'serve:docs:hot', 'watch:docs')) diff --git a/build/gulp/tasks/perf.ts b/build/gulp/tasks/perf.ts index 0d1b8bf7df..53726a1a2b 100644 --- a/build/gulp/tasks/perf.ts +++ b/build/gulp/tasks/perf.ts @@ -1,10 +1,10 @@ -import express from 'express' -import fs from 'fs' +import * as express from 'express' +import * as fs from 'fs' import { task, series } from 'gulp' -import _ from 'lodash' +import * as _ from 'lodash' import ProgressBar from 'progress' -import puppeteer from 'puppeteer' -import rimraf from 'rimraf' +import * as puppeteer from 'puppeteer' +import * as rimraf from 'rimraf' import { argv } from 'yargs' import { diff --git a/build/gulp/tasks/screener.ts b/build/gulp/tasks/screener.ts index ff0f9b22a4..972110ce27 100644 --- a/build/gulp/tasks/screener.ts +++ b/build/gulp/tasks/screener.ts @@ -29,5 +29,4 @@ task('screener:runner', cb => { // ---------------------------------------- // Default // ---------------------------------------- - -task('screener', series('build:docs', 'serve:docs', 'screener:runner')) +task('screener', series('serve:docs', 'screener:runner')) diff --git a/build/gulp/tasks/stats.ts b/build/gulp/tasks/stats.ts index 2d700ad165..9c88922575 100644 --- a/build/gulp/tasks/stats.ts +++ b/build/gulp/tasks/stats.ts @@ -1,6 +1,6 @@ -import fs from 'fs' +import * as fs from 'fs' import { task, parallel, series } from 'gulp' -import _ from 'lodash' +import * as _ from 'lodash' import webpack from 'webpack' import stableStringify from 'json-stable-stringify-without-jsonify' import { argv } from 'yargs' @@ -129,10 +129,7 @@ task('stats:build:bundle', async () => { writeCurrentStats(currentStatsFilePath, results) }) -task( - 'stats', - series(parallel('bundle:all-packages', 'build:docs:component-info'), 'stats:build:bundle'), -) +task('stats', series(parallel('bundle:all-packages', 'build:docs'), 'stats:build:bundle')) function readSummaryPerfStats() { return _.chain(require(paths.perfDist('result.json'))) diff --git a/build/gulp/tasks/test-circulars/index.ts b/build/gulp/tasks/test-circulars/index.ts index f1ac92235b..7d78525461 100644 --- a/build/gulp/tasks/test-circulars/index.ts +++ b/build/gulp/tasks/test-circulars/index.ts @@ -1,5 +1,5 @@ -import path from 'path' -import fs from 'fs' +import * as path from 'path' +import * as fs from 'fs' import { task, series } from 'gulp' import webpackPlugin from '../../plugins/gulp-webpack' diff --git a/build/gulp/tasks/test-circulars/utils.ts b/build/gulp/tasks/test-circulars/utils.ts index e009270517..15c731bf24 100644 --- a/build/gulp/tasks/test-circulars/utils.ts +++ b/build/gulp/tasks/test-circulars/utils.ts @@ -1,4 +1,4 @@ -import path from 'path' +import * as path from 'path' import CircularDependencyPlugin from 'circular-dependency-plugin' import config from '../../../../config' diff --git a/build/gulp/tasks/test-e2e.ts b/build/gulp/tasks/test-e2e.ts index e3107b3851..6043f2f0f6 100644 --- a/build/gulp/tasks/test-e2e.ts +++ b/build/gulp/tasks/test-e2e.ts @@ -1,6 +1,6 @@ import { task, series } from 'gulp' import * as yargs from 'yargs' -import rimraf from 'rimraf' +import * as rimraf from 'rimraf' import config from '../../../config' import webpackPlugin from '../plugins/gulp-webpack' diff --git a/build/gulp/tasks/test-projects.ts b/build/gulp/tasks/test-projects.ts index 7281642d2b..f401e49b8b 100644 --- a/build/gulp/tasks/test-projects.ts +++ b/build/gulp/tasks/test-projects.ts @@ -1,16 +1,16 @@ -import express from 'express' -import fs from 'fs' +import * as express from 'express' +import * as fs from 'fs' import { series, task } from 'gulp' import { rollup as lernaAliases } from 'lerna-alias' -import path from 'path' -import portfinder from 'portfinder' -import puppeteer from 'puppeteer' +import * as path from 'path' +import * as portfinder from 'portfinder' +import * as puppeteer from 'puppeteer' import sh from '../sh' -import rimraf from 'rimraf' +import * as rimraf from 'rimraf' import config from '../../../config' -import tmp from 'tmp' -import http from 'http' +import * as tmp from 'tmp' +import * as http from 'http' import { safeLaunchOptions } from 'build/puppeteer.config' type PackedPackages = Record diff --git a/build/gulp/tasks/test-unit.ts b/build/gulp/tasks/test-unit.ts index 5876285aea..10530859d5 100644 --- a/build/gulp/tasks/test-unit.ts +++ b/build/gulp/tasks/test-unit.ts @@ -1,5 +1,5 @@ -import { parallel, series, task } from 'gulp' -import yargs from 'yargs' +import { series, task } from 'gulp' +import * as yargs from 'yargs' import sh from '../sh' import jest, { JestPluginConfig } from '../plugins/gulp-jest' @@ -21,13 +21,7 @@ const jestConfigFromArgv: Partial = { task('test:jest:pre', () => sh('yarn satisfied')) -task( - 'test:jest:setup', - series( - 'test:jest:pre', - parallel('build:docs:component-info', 'build:docs:component-menu-behaviors'), - ), -) +task('test:jest:setup', series('test:jest:pre', 'build:docs')) task( 'test:jest', @@ -52,4 +46,4 @@ task( // ---------------------------------------- task('test', series('test:jest:setup', 'test:jest')) -task('test:watch', series('test:jest:setup', parallel('test:jest:watch', 'watch:docs'))) +task('test:watch', series('test:jest:setup', 'test:jest:watch')) diff --git a/build/screener/screener.states.ts b/build/screener/screener.states.ts index 7519166cd4..3f5a671515 100644 --- a/build/screener/screener.states.ts +++ b/build/screener/screener.states.ts @@ -42,9 +42,5 @@ const getStateForPath = (examplePath: string) => { } } -const screenerStates = filteredPaths.reduce((states, examplePath) => { - states.push(getStateForPath(examplePath)) - return states -}, []) - +const screenerStates = filteredPaths.map(getStateForPath) export default screenerStates diff --git a/build/webpack.config.ts b/build/webpack.config.ts index d9dbe03aa8..e6f91f15a7 100644 --- a/build/webpack.config.ts +++ b/build/webpack.config.ts @@ -62,7 +62,7 @@ const webpackConfig: any = { }, { test: /\.mdx?$/, - use: ['babel-loader', '@mdx-js/loader'], + use: ['babel-loader'], }, ], }, diff --git a/docs-v2/.eslintignore b/docs-v2/.eslintignore new file mode 100644 index 0000000000..db94ef93ac --- /dev/null +++ b/docs-v2/.eslintignore @@ -0,0 +1,5 @@ +.stardust-ui-react +component-info +public +content/components +src/examples diff --git a/docs-v2/.gitignore b/docs-v2/.gitignore new file mode 100644 index 0000000000..edb604012e --- /dev/null +++ b/docs-v2/.gitignore @@ -0,0 +1,7 @@ +.DS_STORE +*.log +.idea +.vscode +.cache +node_modules +public diff --git a/docs-v2/.prettierignore b/docs-v2/.prettierignore new file mode 100644 index 0000000000..18275671c7 --- /dev/null +++ b/docs-v2/.prettierignore @@ -0,0 +1,4 @@ +*.html +*.md +.cache +public diff --git a/docs-v2/README.md b/docs-v2/README.md new file mode 100644 index 0000000000..67eb4f0aa7 --- /dev/null +++ b/docs-v2/README.md @@ -0,0 +1,19 @@ +# Stardust UI Documentation + +You need **node >= 8.0.0** to build this project. + +```sh +# Clone: +git clone https://github.com/davezuko/stardust-ui-docs +cd stardust-ui-docs + +# Install dependencies: +yarn + +# Open the new docs: +cd docs-v2 + +# Run one of these: +yarn build # build site to disk +yarn start # start site at localhost:3000 +``` diff --git a/docs-v2/gatsby-browser.js b/docs-v2/gatsby-browser.js new file mode 100644 index 0000000000..e5f31d2bf9 --- /dev/null +++ b/docs-v2/gatsby-browser.js @@ -0,0 +1,24 @@ +import "./src/global-css/main.css" +import {autorun} from "mobx" +import {store, wrapRootElement} from "./src/wrap-root-element" + +// Wrap the React tree in our providers +export {wrapRootElement} + +// Watch for changes to the global theme; changing the theme causes the new +// theme to be downloaded and applied to the document. +autorun(() => loadTheme(store.theme)) +async function loadTheme(theme) { + localStorage.setItem("theme", theme) + switch (theme) { + case "light": + await import("./src/global-css/themes/light.css") + break + case "dark": + await import("./src/global-css/themes/dark.css") + break + default: + throw new Error("Unknown theme: " + theme) + } + document.body.setAttribute("data-theme", theme) +} diff --git a/docs-v2/gatsby-config.js b/docs-v2/gatsby-config.js new file mode 100644 index 0000000000..0675d44e7e --- /dev/null +++ b/docs-v2/gatsby-config.js @@ -0,0 +1,108 @@ +const path = require("path") + +module.exports = { + siteMetadata: { + title: "Stardust UI", + siteUrl: "https://stardust.zuko.me", + description: "An accessible, themable component library for the web", + author: "Microsoft" + }, + plugins: [ + "gatsby-plugin-sitemap", + "gatsby-plugin-typescript", + "gatsby-plugin-react-helmet", + "gatsby-plugin-catch-links", + "gatsby-transformer-sharp", + "gatsby-plugin-sharp", + "gatsby-plugin-remove-trailing-slashes", + "gatsby-source-component-schemas", + { + resolve: "gatsby-source-filesystem", + options: { + name: "learn", + path: `${__dirname}/src/pages/learn` + } + }, + { + resolve: "gatsby-source-filesystem", + options: { + name: "components", + path: `${__dirname}/src/pages/components` + } + }, + { + resolve: "gatsby-plugin-mdx", + options: { + gatsbyRemarkPlugins: [ + { + resolve: `gatsby-remark-prismjs`, + options: { + showLineNumbers: false, + noInlineHighlight: true, + languageExtensions: [] + } + } + ], + defaultLayouts: { + default: require.resolve("./src/templates/single.js"), + components: require.resolve("./src/templates/components/single.js"), + learn: require.resolve("./src/templates/learn/single.js") + } + } + }, + { + resolve: "gatsby-plugin-manifest", + options: { + name: "Stardust UI", + short_name: "stardust", + start_url: "/", + background_color: "#663399", + theme_color: "#663399", + display: "minimal-ui", + icon: "static/favicon.png" + } + }, + { + resolve: "gatsby-plugin-google-analytics", + options: { + trackingId: "UA-48163724-5", + head: false, + respectDNT: true + } + }, + // Alias all @stardust-ui imports so that they are imported from the + // monorepo. This allows developers to make changes to the Stardust library + // and see them in the doc site without any additional build step. + { + resolve: "gatsby-plugin-alias-imports", + options: { + alias: { + "@stardust-ui/react": path.resolve( + __dirname, + "../packages/react/src" + ), + "@stardust-ui/accessibility": path.resolve( + __dirname, + "../packages/accessibility/src" + ), + "@stardust-ui/react-component-event-listener": path.resolve( + __dirname, + "../packages/react-component-event-listener/src" + ), + "@stardust-ui/react-component-nesting-registry": path.resolve( + __dirname, + "../packages/react-component-nesting-registry/src" + ), + "@stardust-ui/react-component-ref": path.resolve( + __dirname, + "../packages/react-component-ref/src" + ), + "@stardust-ui/react-proptypes": path.resolve( + __dirname, + "../packages/react-proptypes/src" + ) + } + } + } + ] +} diff --git a/docs-v2/gatsby-node.js b/docs-v2/gatsby-node.js new file mode 100644 index 0000000000..3ef07eee2a --- /dev/null +++ b/docs-v2/gatsby-node.js @@ -0,0 +1,123 @@ +const inspect = require("./tools/inspect") + +// FIXME: this gets initialized in createPages(), and is later used to inject +// additional context into component detail pages in onCreatePage(). I don't +// believe onCreatePage supports async actions, which is why this exists. +// Investigate whether or not that's actually true. +let componentSchemas + +// Generates all dynamic pages for the website (pages that do not have a file +// in ./src/pages). Always prefer creating a page in src/pages. +exports.createPages = async function({actions}) { + // Generate /components/:name/playground for each component + componentSchemas = await inspect.components() + for (const schema of componentSchemas) { + const page = makeComponentPlaygroundPage(schema) + actions.createPage(page) + } +} + +// Injects dynamic content into generated pages. This function should be used +// sparingly to avoid diverging too far from Gatsby core. +exports.onCreatePage = function({page, actions}) { + const originalPage = page + + // We avoid adding `category` to many pages' frontmatter because they are + // already categorized by their location in /pages. Add it at build time. + // TODO: should probably just add it to frontmatter for clarity... + page = injectPageCategory(page) + + // FIXME: Remove when possible. Component detail pages need access to the + // component JSON schema, but I'm not sure how to supply this information + // over a static graphql query in gatsby. + if ( + page.context.frontmatter && + page.context.frontmatter.category === "Components" && + page.path !== "/components" && + !/playground/.test(page.path) + ) { + page = injectComponentSchema(page) + } + if (page !== originalPage) { + actions.deletePage(originalPage) + actions.createPage(page) + } +} + +// Do not further modify the webpack configuration! This override exists +// solely to fix an issue with Gatsby loading multiple React instances. +// FIXME: investigate root cause +exports.onCreateWebpackConfig = function({getConfig, stage}) { + const config = getConfig() + config.resolve.alias = { + ...config.resolve.alias, + react: require.resolve("react") + } +} + +function makeComponentPlaygroundPage(component) { + return { + path: `/components/${component.slug}/playground`, + component: require.resolve( + "./src/templates/components/standalone-playground.js" + ), + context: { + schema: component + } + } +} + +function injectPageCategory(page) { + // Page already has a category. + if (page.context.frontmatter && page.context.frontmatter.category) { + return page + } + + let category + switch (true) { + case /\/learn/.test(page.path): + category = "Learn" + break + case /\/components/.test(page.path): + category = "Components" + break + default: + category = "Site" + } + return { + ...page, + context: { + ...page.context, + frontmatter: { + ...page.context.frontmatter, + category + } + } + } +} + +function injectComponentSchema(page) { + const slug = page.path.replace("/components/", "") + const schema = componentSchemas.find(schema => schema.slug === slug) + if (!schema) { + console.error( + 'No schema found for page "%s" (looked up slug: "%s").', + page.path, + slug + ) + return page + } + + return { + ...page, + context: { + ...page.context, + schema, + frontmatter: { + title: schema.displayName, + description: schema.description, + ...page.context.frontmatter + } + } + } +} diff --git a/docs-v2/gatsby-ssr.js b/docs-v2/gatsby-ssr.js new file mode 100644 index 0000000000..52e84f5dc9 --- /dev/null +++ b/docs-v2/gatsby-ssr.js @@ -0,0 +1,20 @@ +import React from "react" +export {wrapRootElement} from "./src/wrap-root-element" + +// FIXME +// We set the global font size to 10px in src/global-css/main.css, but Gatsby +// isn't guaranteed to inject that style before Stardust loads. Thus, there's +// a race condition: if Stardust initializes before that font size is applied, +// it will think that the base font size is 16px (the default) instead of 10, +// and compute all of its rem values based on that incorrect base size. +export function onRenderBody({setHeadComponents}) { + setHeadComponents([ + React.createElement("script", { + dangerouslySetInnerHTML: { + __html: ` + document.documentElement.style.fontSize = "10px" + ` + } + }) + ]) +} diff --git a/docs-v2/package.json b/docs-v2/package.json new file mode 100644 index 0000000000..c807d78a86 --- /dev/null +++ b/docs-v2/package.json @@ -0,0 +1,65 @@ +{ + "name": "stardust-ui-docs", + "version": "1.0.0", + "repository": "git@github.com:davezuko/stardust-ui-docs", + "author": "David Zukowski ", + "license": "MIT", + "sideEffects": [ + "*.css" + ], + "scripts": { + "build": "gatsby build", + "start": "gatsby develop --port 3000", + "serve": "gatsby serve", + "lint": "eslint .", + "test-ci": "node tools/run-ci-tests.js" + }, + "eslintConfig": { + "extends": "react-app" + }, + "prettier": { + "semi": false, + "bracketSpacing": false + }, + "devDependencies": { + "@mdx-js/mdx": "^1.5.0", + "@mdx-js/react": "^1.5.0", + "eslint-config-react-app": "^5.0.1", + "express": "^4.17.1", + "front-matter": "^3.0.2", + "gatsby": "^2.15.28", + "gatsby-cli": "^2.7.53", + "gatsby-image": "^2.2.23", + "gatsby-plugin-alias-imports": "^1.0.5", + "gatsby-plugin-catch-links": "^2.1.12", + "gatsby-plugin-google-analytics": "^2.1.19", + "gatsby-plugin-manifest": "^2.2.20", + "gatsby-plugin-mdx": "^1.0.46", + "gatsby-plugin-offline": "^3.0.11", + "gatsby-plugin-react-helmet": "^3.1.10", + "gatsby-plugin-remove-trailing-slashes": "^2.1.9", + "gatsby-plugin-sharp": "^2.2.27", + "gatsby-plugin-sitemap": "^2.2.16", + "gatsby-plugin-typescript": "^2.1.11", + "gatsby-remark-prismjs": "^3.3.16", + "gatsby-source-filesystem": "^2.1.28", + "gatsby-transformer-remark": "^2.6.26", + "gatsby-transformer-sharp": "^2.2.19", + "prettier": "^1.18.2", + "ts-node-alias-to-fix-gulp-conflict": "npm:ts-node@^8.4.1", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^1.2.23", + "@fortawesome/free-brands-svg-icons": "^5.11.2", + "@fortawesome/free-regular-svg-icons": "^5.11.0", + "@fortawesome/free-solid-svg-icons": "^5.11.0", + "@fortawesome/react-fontawesome": "^0.1.5", + "normalize.css": "^8.0.1", + "prismjs": "^1.17.1", + "react": "^16.9.0", + "react-ace": "^7.0.4", + "react-dom": "^16.9.0", + "react-helmet": "^5.2.1" + } +} diff --git a/docs-v2/packages/playground/api.js b/docs-v2/packages/playground/api.js new file mode 100644 index 0000000000..2992221dc1 --- /dev/null +++ b/docs-v2/packages/playground/api.js @@ -0,0 +1,174 @@ +import React from "react" +import {observable, action, decorate} from "mobx" +import * as Stardust from "@stardust-ui/react" +import * as Babel from "@babel/standalone" +import Prettier from "prettier/standalone" +import BabylonParser from "prettier/parser-babylon" + +// Previews assume that React and Stardust components are available in their +// current scope, so we must provide them. +if (typeof window !== "undefined") { + window.React = React + for (let key in Stardust) { + window[key] = Stardust[key] + } +} + +export class PlaygroundAPI { + rtl = false + transparent = false + themes = [ + {id: "Teams Light", value: Stardust.themes.teams}, + {id: "Teams Dark", value: Stardust.themes.teamsDark}, + {id: "Teams High Contrast", value: Stardust.themes.teamsDark} + ] + + constructor(schema) { + this.schema = schema + this.theme = this.themes[0] + if (schema.examples && schema.examples.length > 0) { + this.examples = sortExamples( + schema.examples.map(example => new Example(example)) + ) + this.selectExample(this.examples[0].title) + } else { + this.examples = [] + } + + // Bind methods + this.toggleRTL = this.toggleRTL.bind(this) + this.toggleTransparent = this.toggleTransparent.bind(this) + this.selectExample = this.selectExample.bind(this) + this.selectTheme = this.selectTheme.bind(this) + } + + selectControl(label) { + this.activeControl = label + } + + selectTheme(id) { + const theme = this.themes.find(theme => theme.id === id) + if (theme) { + this.theme = theme + } + } + + selectExample(title) { + if (this.activeExample) { + this.activeExample.active = false + } + this.activeExample = this.examples.find(example => example.title === title) + this.activeExample.active = true + } + + toggleRTL() { + this.rtl = !this.rtl + } + + toggleTransparent() { + this.transparent = !this.transparent + } + + reset() { + if (this.activeExample) { + this.activeExample.reset() + } + } + + render() { + if (!this.activeExample) { + return
+ } + return this.activeExample.render() + } +} +decorate(PlaygroundAPI, { + rtl: observable, + transparent: observable, + theme: observable.shallow, + activeExample: observable.shallow, + selectTheme: action, + selectExample: action, + toggleRTL: action, + toggleTransparent: action +}) + +function sortExamples(examples) { + return examples.sort((a, b) => { + if (a.title === "Default") { + return -1 + } + if (b.title === "Default") { + return 1 + } + return 0 + }) +} + +export class Example { + active = false + + constructor(json) { + this.title = json.title + .replace(/\..*/, "") + .split("-") + .map(word => word[0].toUpperCase() + word.slice(1).toLowerCase()) + .join(" ") + this.description = json.description + this._originalSource = this.normalizeSource(json.source) + this.source = this._originalSource + } + + normalizeSource(source) { + source = source + .split("\n") + .filter(line => !/^\/\//.test(line)) + .join("\n") + return source + } + + format() { + this.source = Prettier.format(this.source, { + semi: false, + bracketSpacing: false, + parser: "babylon", + plugins: [BabylonParser] + }) + } + + reset() { + this.source = this._originalSource + } + + render() { + let source = this.source + + // strip imports + source = source + .split("\n") + .filter(line => !/^import/.test(line)) + .join("\n") + + // replace default export + source = source.replace("export default", "return") + source = `(() => { ${source} })()` + try { + source = Babel.transform(source, {presets: ["react"]}).code + const result = eval(source) // eslint-disable-line + if (typeof result === "function") { + return React.createElement(result) + } else { + return result + } + } catch (e) { + console.error(e) + return null + } + } +} +decorate(Example, { + active: observable, + source: observable, + format: action, + reset: action +}) diff --git a/docs-v2/packages/playground/context.js b/docs-v2/packages/playground/context.js new file mode 100644 index 0000000000..803a05c0b4 --- /dev/null +++ b/docs-v2/packages/playground/context.js @@ -0,0 +1,9 @@ +import React from "react" + +const PlaygroundContext = React.createContext() + +export const PlaygroundProvider = PlaygroundContext.Provider + +export function usePlayground() { + return React.useContext(PlaygroundContext) +} diff --git a/docs-v2/packages/playground/examples.js b/docs-v2/packages/playground/examples.js new file mode 100644 index 0000000000..acbac25926 --- /dev/null +++ b/docs-v2/packages/playground/examples.js @@ -0,0 +1,38 @@ +import React from "react" +import {observer} from "mobx-react" +import {usePlayground} from "./context" + +export const PlaygroundExamples = () => { + const playground = usePlayground() + + return ( +
+
    + {playground.examples.map(example => { + return ( + playground.selectExample(title)} + /> + ) + })} +
+
+ ) +} + +const Example = observer(({example, onSelect}) => { + let className = "playground-example is-selectable" + if (example.active) { + className += " is-selected" + } + return ( +
  • onSelect(example.title)}> + {example.title} + + {example.description} + +
  • + ) +}) diff --git a/docs-v2/packages/playground/index.css b/docs-v2/packages/playground/index.css new file mode 100644 index 0000000000..b88fc1b515 --- /dev/null +++ b/docs-v2/packages/playground/index.css @@ -0,0 +1,136 @@ +.playground { + color: var(--sui-color) !important; + border: 1px solid var(--sui-card-border-color); + border-radius: 0.25rem; +} + +.playground-body { + display: flex; + flex-direction: row-reverse; + height: 35rem; +} + +.playground-banner { + display: flex; + padding: 1rem; + background: var(--sui-playground-banner-background); + border-bottom: 1px solid var(--sui-card-border-color); +} + +.playground-maximize { + margin-left: auto; + padding: 0; + font-size: 1.75rem; + color: var(--sui-color); + background: none; + outline: none; + border: none; + cursor: pointer; + opacity: 0.75; +} + +.playground-maximize:hover { + opacity: 1; +} + +.playground-preview-controls { + display: flex; +} + +.playground-preview-control { + display: flex; + align-items: center; +} + +.playground-preview-control-label { + display: block; + font-weight: bold; + margin: 0 1rem 0 0; + color: var(--sui-color); +} + +.playground-preview { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + padding: 2rem; +} + +.playground-examples { + position: relative; + display: flex; + width: 25rem; + flex-direction: column; + max-height: 100%; + overflow: auto; +} + +.playground-example-list { + list-style: none; + margin: 0; + padding: 0; +} + +.playground-example { + position: relative; + padding: 1rem; + border-bottom: 1px solid #ddd !important; +} + +.playground-example-title { + display: block; + font-weight: bold; +} + +@media screen and (max-width: 950px) { + .playground-body { + display: block; + } + + .playground-banner-rail-title { + display: none; + } + + .playground-examples { + max-height: 12rem; + } +} + +@media screen and (max-width: 568px) { + .playground-preview-controls { + display: block; + } + + .playground-preview-control { + margin: 0 0 0.75rem; + } + + .playground-preview-control:last-of-type { + margin: 0; + } + + .playground-preview-control-label { + width: 10rem; + } + + .playground-preview-control .ui-checkbox { + padding: 0 !important; + } + + .playground-preview-control .ui-checkbox .ui-icon { + margin-left: -0.3rem; + } + + .playground-banner { + display: block; + } + + .playground-banner-rail-title { + display: block; + margin: 1.5rem -1rem 0; + padding: 1rem 1rem 0 1rem; + border-top: 1px solid #ddd; + } +} diff --git a/docs-v2/packages/playground/index.js b/docs-v2/packages/playground/index.js new file mode 100644 index 0000000000..ac8f874cac --- /dev/null +++ b/docs-v2/packages/playground/index.js @@ -0,0 +1 @@ +export {Playground} from "./playground" diff --git a/docs-v2/packages/playground/package.json b/docs-v2/packages/playground/package.json new file mode 100644 index 0000000000..2908355a01 --- /dev/null +++ b/docs-v2/packages/playground/package.json @@ -0,0 +1,24 @@ +{ + "name": "@standard-ui-docs/playground", + "version": "1.0.0", + "repository": "git@github.com:davezuko/stardust-ui-docs", + "author": "David Zukowski ", + "license": "MIT", + "main": "index.js", + "sideEffects": [ + "*.css" + ], + "dependencies": { + "@babel/standalone": "^7.6.0", + "@fortawesome/fontawesome-svg-core": "^1.2.23", + "@fortawesome/free-regular-svg-icons": "^5.11.0", + "@fortawesome/free-solid-svg-icons": "^5.11.0", + "@fortawesome/react-fontawesome": "^0.1.5", + "@stardust-ui/react": "^0.39.0", + "brace": "^0.11.1", + "mobx": "^5.14.0", + "mobx-react": "^6.1.3", + "mobx-utils": "^5.4.1", + "react-ace": "^7.0.4" + } +} diff --git a/docs-v2/packages/playground/playground.js b/docs-v2/packages/playground/playground.js new file mode 100644 index 0000000000..8905f6a0db --- /dev/null +++ b/docs-v2/packages/playground/playground.js @@ -0,0 +1,122 @@ +import "./index.css" +import React from "react" +import {observer} from "mobx-react" +import {FontAwesomeIcon} from "@fortawesome/react-fontawesome" +import {faExpandArrowsAlt} from "@fortawesome/free-solid-svg-icons" +import { + themes, + Provider as StardustProvider, + Checkbox +} from "@stardust-ui/react" +import {usePlayground} from "./context" +import {PlaygroundExamples} from "./examples" +import {PlaygroundPreview} from "./preview" +import {PlaygroundProvider} from "./context" +import {PlaygroundAPI} from "./api" + +export function Playground({schema, onRequestMaximize}) { + const playground = React.useMemo(() => new PlaygroundAPI(schema), [schema]) + const stardustTheme = themes.teams + + // FIXME: errors thrown from Stardust during server-side rendering + if (typeof window === "undefined") { + return null + } + + return ( + + +
    + +
    + + +
    +
    +
    +
    + ) +} + +function PlaygroundBanner({onRequestMaximize}) { + return ( +
    +
    + + + +
    + +
    + ) +} + +const ThemeControl = observer(() => { + const playground = usePlayground() + + function handleChange(e) { + playground.selectTheme(e.target.value) + } + + return ( +
    + Theme: + +
    + ) +}) + +const RTLControl = observer(() => { + const playground = usePlayground() + + const label = ( + + RTL + + ) + return ( +
    + +
    + ) +}) + +const TransparencyControl = observer(() => { + const playground = usePlayground() + + const label = ( + + Transparency + + ) + return ( +
    + +
    + ) +}) diff --git a/docs-v2/packages/playground/plugin-host.css b/docs-v2/packages/playground/plugin-host.css new file mode 100644 index 0000000000..5cf50c9d75 --- /dev/null +++ b/docs-v2/packages/playground/plugin-host.css @@ -0,0 +1,39 @@ +.playground-plugin-host { + min-width: 0; + border-top: 1px solid var(--sui-card-border-color); +} + +.playground-plugin-host__nav { + display: flex; + background: var(--sui-playground-banner-background); + border: 1px solid var(--sui-card-border-color); + border-top: none; +} + +.playground-plugin-link { + position: relative; + display: block; + padding: 1rem 0.75rem; + font-size: 1.9rem; + color: inherit; + text-decoration: none; + outline: none; + border: none; + background: none; + cursor: pointer; +} + +.playground-plugin-link.is-active { + font-weight: bold; +} + +.playground-plugin-link.is-active::after { + content: ""; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 0.2rem; + background: var(--sui-accent-color); + box-shadow: 0 0 3px 0 var(--sui-accent-color); +} diff --git a/docs-v2/packages/playground/plugin-host.js b/docs-v2/packages/playground/plugin-host.js new file mode 100644 index 0000000000..0cdb9fed44 --- /dev/null +++ b/docs-v2/packages/playground/plugin-host.js @@ -0,0 +1,38 @@ +import React from "react" +import "./plugin-host.css" + +export function PlaygroundPluginHost({schema, plugins}) { + const [activePlugin, setActivePlugin] = React.useState() + return ( +
    + +
    + {activePlugin && activePlugin.render({schema})} +
    +
    + ) +} diff --git a/docs-v2/packages/playground/plugins/editor-plugin.js b/docs-v2/packages/playground/plugins/editor-plugin.js new file mode 100644 index 0000000000..d37d21b834 --- /dev/null +++ b/docs-v2/packages/playground/plugins/editor-plugin.js @@ -0,0 +1,62 @@ +import React from "react" +import {observer} from "mobx-react" +import {usePlayground} from "../context" + +let AceEditor + +const Editor = observer(() => { + const ace = React.useRef() + const playground = usePlayground() + + React.useMemo(() => { + if (typeof window !== "undefined") { + AceEditor = require("react-ace").default + require("brace") + require("brace/ext/language_tools") + require("brace/mode/jsx") + require("brace/theme/dracula") + } + }, []) + + function handleChange(source) { + playground.activeExample.source = source + } + + if (!AceEditor || !playground.activeExample) { + return null + } + + const value = playground.activeExample.source + return ( +
    + +
    + ) +}) + +export default { + title: "Editor", + render() { + return + } +} diff --git a/docs-v2/packages/playground/plugins/html-plugin.js b/docs-v2/packages/playground/plugins/html-plugin.js new file mode 100644 index 0000000000..3bb620460b --- /dev/null +++ b/docs-v2/packages/playground/plugins/html-plugin.js @@ -0,0 +1,6 @@ +export default { + title: "HTML", + render() { + return null + } +} diff --git a/docs-v2/packages/playground/plugins/styles-plugin.js b/docs-v2/packages/playground/plugins/styles-plugin.js new file mode 100644 index 0000000000..dd436a8443 --- /dev/null +++ b/docs-v2/packages/playground/plugins/styles-plugin.js @@ -0,0 +1,6 @@ +export default { + title: "Styles", + render() { + return null + } +} diff --git a/docs-v2/packages/playground/preview.js b/docs-v2/packages/playground/preview.js new file mode 100644 index 0000000000..e6dd166374 --- /dev/null +++ b/docs-v2/packages/playground/preview.js @@ -0,0 +1,70 @@ +import React from "react" +import {observer} from "mobx-react" +import {Provider} from "@stardust-ui/react" +import {usePlayground} from "./context" + +// prettier-ignore +const TRANSPARENT_BACKGROUND = "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAKUlEQVQoU2NkYGAwZkAD////RxdiYBwKCv///4/hGUZGkNNRAeMQUAgAtxof+nLDzyUAAAAASUVORK5CYII=)" + +export const PlaygroundPreview = observer(() => { + const playground = usePlayground() + + let styles + let theme = playground.theme.value + + if (playground.transparent) { + styles = {background: TRANSPARENT_BACKGROUND} + } + // Override the container background if the theme has a white background; + // prefer a dim background. + else if (theme.siteVariables.bodyBackground === "#fff") { + styles = {background: "#ddd !important"} + } + + // HACK: force re-render when active example changes + // eslint-disable-next-line + playground.activeExample && playground.activeExample.source + + function handleClick(e) { + e.preventDefault() + e.stopPropagation() + } + + return ( + + + {playground.render()} + + + ) +}) + +class PlaygroundPreviewErrorBoundary extends React.Component { + state = { + error: null + } + + componentDidCatch(error) { + this.setState({error}) + } + + render() { + if (this.state.error) { + return ( +
    +

    An error occured while rendering this component:

    +
    {this.state.error.message}
    +
    + ) + } + return this.props.children || null + } +} diff --git a/docs-v2/packages/prop-table/index.css b/docs-v2/packages/prop-table/index.css new file mode 100644 index 0000000000..8933d40a8e --- /dev/null +++ b/docs-v2/packages/prop-table/index.css @@ -0,0 +1,64 @@ +.sui-prop-table-container { + -webkit-overflow-scrolling: touch; + overflow: auto; + overflow-y: hidden; + max-width: 100%; +} + +.sui-prop-table { + width: 100%; + color: inherit; + background: var(--sui-table-background, #fff); + border-collapse: collapse; + border: 1px solid var(--sui-table-border-color, #dbdbdb); + border-bottom: none; + font-size: 1.5rem; +} + +.sui-prop-table .no-wrap { + white-space: nowrap; +} + +.sui-prop-table td, +.sui-prop-table th { + border: 1px solid var(--sui-table-cell-border-color, #dbdbdb); + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; +} + +.sui-prop-table th { + color: var(--sui-table-header-cell-color, inherit); +} + +.sui-prop-table th:not([align]) { + text-align: left; +} + +.sui-prop-table thead { + background-color: var(--sui-table-header-background, transparent); +} + +.sui-prop-table thead td, +.sui-prop-table thead th { + border-width: 0 0 2px; + color: var(--sui-table-color, #363636); +} + +.sui-prop-table tbody { + background-color: transparent; +} + +.sui-prop-table tbody tr:last-child td, +.sui-prop-table tbody tr:last-child th { + border-bottom-width: 0; +} + +.sui-prop-table.is-narrow td, +.sui-prop-table.is-narrow th { + padding: 0.25em 0.5em; +} + +.sui-prop-table tbody tr:not(.is-selected):nth-child(even) { + background-color: var(--sui-table-striped-row-background, #fafafa); +} diff --git a/docs-v2/packages/prop-table/index.js b/docs-v2/packages/prop-table/index.js new file mode 100644 index 0000000000..46dc446451 --- /dev/null +++ b/docs-v2/packages/prop-table/index.js @@ -0,0 +1,60 @@ +import "./index.css" +import React from "react" + +export function PropTable({props}) { + return ( +
    + + + + + + + + + + + {props && + props.map(prop => { + return ( + + + + + + + ) + })} + +
    NameTypeDefault ValueDescription
    {prop.name}{renderPropTypes(prop.types)}{renderDefaultValue(prop)}{prop.description}
    +
    + ) +} + +function renderPropTypes(types) { + if (!types) { + return null + } + return types + .map(type => { + if (type.name === "literal") { + return '"' + type.value + '"' + } + + return type.name + }) + .join(" | ") +} + +function renderDefaultValue(prop) { + const {defaultValue} = prop + if (typeof defaultValue === "undefined") { + return "-" + } else if (!defaultValue) { + return "" + defaultValue + } else if (typeof defaultValue === "object") { + return JSON.stringify(defaultValue) + } else { + return defaultValue + } +} diff --git a/docs-v2/packages/prop-table/package.json b/docs-v2/packages/prop-table/package.json new file mode 100644 index 0000000000..967ba97b26 --- /dev/null +++ b/docs-v2/packages/prop-table/package.json @@ -0,0 +1,9 @@ +{ + "name": "@standard-ui-docs/prop-table", + "version": "1.0.0", + "repository": "git@github.com:davezuko/stardust-ui-docs", + "author": "David Zukowski ", + "license": "MIT", + "main": "index.js", + "sideEffects": ["*.css"] +} diff --git a/docs-v2/packages/search/index.css b/docs-v2/packages/search/index.css new file mode 100644 index 0000000000..b91b81b2cc --- /dev/null +++ b/docs-v2/packages/search/index.css @@ -0,0 +1,83 @@ +.sui-search { + position: relative; + width: 100%; + z-index: 1; +} + +.sui-search__input { + width: 100%; + padding: 1rem; + font-size: 1.5rem; + outline: none; + color: var(--sui-color); + border: none; + border-radius: 0.5rem; + background: var(--sui-search-background); +} + +.sui-search__input::-webkit-input-placeholder { + color: var(--sui-search-placeholder-color); +} +.sui-search__input::-moz-placeholder { + color: var(--sui-search-placeholder-color); +} +.sui-search__input:-ms-input-placeholder { + color: var(--sui-search-placeholder-color); +} +.sui-search__input:-moz-placeholder { + color: var(--sui-search-placeholder-color); +} + +.sui-search__input.is-mobile { + display: none; +} + +.sui-search__results { + position: absolute; + top: 100%; + width: 100%; + background: var(--sui-card-background); + border: 1px solid var(--sui-card-border-color); + border-radius: 0.25rem; +} + +.sui-search-result-category { + padding: 0.75rem; + background: var(--sui-search-category-background); + color: var(--sui-search-category-foreground, #fff); + font-weight: bold; + font-size: 1.5rem; +} + +.sui-search-result { + display: block; + padding: 0.75rem; + color: inherit !important; + text-decoration: none !important; +} + +.sui-search-result:hover, +.sui-search-result:focus, +.sui-search-result[data-is-selected="true"] { + background: var(--sui-accent-color-background); +} + +.sui-search-result__title { + display: block; + font-weight: bold; +} + +.sui-search-result__description { + display: block; + margin: 0; +} + +@media screen and (max-width: 568px) { + .sui-search__input { + display: none; + } + + .sui-search__input.is-mobile { + display: block; + } +} diff --git a/docs-v2/packages/search/index.js b/docs-v2/packages/search/index.js new file mode 100644 index 0000000000..41921c9d31 --- /dev/null +++ b/docs-v2/packages/search/index.js @@ -0,0 +1,218 @@ +import React from "react" +import {Link} from "gatsby" +import "./index.css" + +export function Search({pages, limit = 5}) { + const [search, setSearch] = React.useState("") + const [selectedResult, setSelectedResult] = React.useState() + const [showResults, setShowResults] = React.useState(true) + const ref = React.useRef() + + // Enable keyboard shortcut to jump to search bar + useKeyboardShortcut() + + React.useEffect(() => { + if (!showResults) { + return + } + + function handleClick(e) { + if (!ref.current.contains(e.target)) { + setShowResults(false) + } + } + + document.addEventListener("click", handleClick) + return () => { + document.removeEventListener("click", handleClick) + } + }, [showResults, ref]) + + // Get search results for current input + const results = React.useMemo(() => { + const results = findMatchingPages(search, pages) + return results.slice(0, limit) + }, [pages, search, limit]) + + // Categorize those results for rendering + const categorizedResults = React.useMemo(() => { + const categories = categorizeResults(results) + + // FIXME: hack for ordering results for keyboard navigation once they've + // been grouped by category. + let idx = 0 + for (const c of categories) { + for (const r of c.results) { + r.index = idx++ + } + } + + return categories + }, [results]) + + // If no result is currently selected, select the first one + React.useLayoutEffect(() => { + if (!results.includes(selectedResult)) { + setSelectedResult(results[0]) + } + }, [results, selectedResult]) + + // Support keyboard navigation (arrow keys to navigate, enter to select) + function handleKeydown(e) { + switch (e.key) { + case "ArrowUp": + case "ArrowDown": { + e.preventDefault() + let currIdx = selectedResult.index || 0 + const nextIdx = + e.key === "ArrowUp" + ? Math.max(currIdx - 1, 0) + : Math.min(currIdx + 1, results.length - 1) + + const result = results.find(r => r.index === nextIdx) + if (result) { + setSelectedResult(result) + } + break + } + case "Enter": + e.preventDefault() + if (selectedResult) { + const selected = document.querySelector( + '.sui-search [data-is-selected="true"]' + ) + if (selected) { + selected.click() + } + } + break + default: + // noop + } + } + + const input = ( + setSearch(e.target.value)} + onKeyDown={handleKeydown} + onFocus={() => setShowResults(true)} + /> + ) + + return ( +
    + {input} + {React.cloneElement(input, { + className: "sui-search__input is-mobile", + placeholder: "Search the docs" + })} + {showResults && categorizedResults.length > 0 && ( + + )} +
    + ) +} + +function SearchResults({categories, selectedResult}) { + return ( +
    + {categories.map(({id, results}, categoryIdx) => { + return ( + +
    {id}
    + {results.map((result, resultIdx) => { + let isSelected = result === selectedResult + if (!selectedResult && !isSelected) { + if (categoryIdx === 0 && resultIdx === 0) { + isSelected = true + } + } + return ( + + + {result.title} + + {result.description && ( + + {result.description} + + )} + + ) + })} +
    + ) + })} +
    + ) +} + +// TODO: prioritize title over description +function findMatchingPages(search, pages) { + search = search.trim() + + if (!search) { + return [] + } + + // TODO: escape regex + const reSearch = new RegExp(search, "i") + const results = [] + for (let i = 0; i < pages.length; i++) { + const page = pages[i] + const isMatch = reSearch.test(page.title) || reSearch.test(page.description) + if (isMatch) { + results.push(page) + } + } + return results +} + +function categorizeResults(results) { + const map = new Map() + for (const result of results) { + if (!map.has(result.category)) { + map.set(result.category, []) + } + map.get(result.category).push(result) + } + + return [...map.entries()].map(([category, results]) => { + return {id: category, results} + }) +} + +function useKeyboardShortcut() { + React.useEffect(() => { + function handleKeydown(e) { + if (e.key === "/") { + const input = [...document.querySelectorAll(".sui-search__input")].find( + isVisible + ) + if (input) { + e.preventDefault() + input.focus() + } + } + } + document.addEventListener("keydown", handleKeydown) + return () => { + document.removeEventListener("keydown", handleKeydown) + } + }, []) +} + +function isVisible(node) { + return node.offsetParent !== null +} diff --git a/docs-v2/packages/search/package.json b/docs-v2/packages/search/package.json new file mode 100644 index 0000000000..adf8c287a1 --- /dev/null +++ b/docs-v2/packages/search/package.json @@ -0,0 +1,9 @@ +{ + "name": "@standard-ui-docs/search", + "version": "1.0.0", + "repository": "git@github.com:davezuko/stardust-ui-docs", + "author": "David Zukowski ", + "license": "MIT", + "main": "index.js", + "sideEffects": ["*.css"] +} diff --git a/docs-v2/plugins/gatsby-source-component-schemas/gatsby-node.js b/docs-v2/plugins/gatsby-source-component-schemas/gatsby-node.js new file mode 100644 index 0000000000..00fb4baeca --- /dev/null +++ b/docs-v2/plugins/gatsby-source-component-schemas/gatsby-node.js @@ -0,0 +1,23 @@ +const inspect = require("../../tools/inspect") + +// TODO: watch for changes to component sources to regenerate schemas +exports.sourceNodes = async function({ + actions, + createNodeId, + createContentDigest +}) { + const components = await inspect.components() + for (let c of components) { + const node = { + ...c, + id: createNodeId(c.displayName), + parent: null, + children: [], // TODO: should include component's children + internal: { + type: "ComponentSchema", + contentDigest: createContentDigest(c) + } + } + actions.createNode(node) + } +} diff --git a/docs-v2/plugins/gatsby-source-component-schemas/package.json b/docs-v2/plugins/gatsby-source-component-schemas/package.json new file mode 100644 index 0000000000..2169513153 --- /dev/null +++ b/docs-v2/plugins/gatsby-source-component-schemas/package.json @@ -0,0 +1,8 @@ +{ + "name": "gatsby-source-component-schemas", + "version": "1.0.0", + "repository": "git@github.com:davezuko/standard-ui-docs", + "author": "David Zukowski ", + "license": "MIT", + "main": "gatsby-node.js" +} diff --git a/docs-v2/src/doc-components/navbar.css b/docs-v2/src/doc-components/navbar.css new file mode 100644 index 0000000000..a048b4319b --- /dev/null +++ b/docs-v2/src/doc-components/navbar.css @@ -0,0 +1,178 @@ +:root { + --sui-navbar-height: 5.75rem; +} + +.navbar { + position: fixed; + top: 0; + display: flex; + align-items: center; + height: var(--sui-navbar-height); + width: 100%; + padding: 0 2rem; + background: var(--sui-navbar-background, #fff); + box-shadow: 0px -9px 17px 10px var(--sui-shadow-color); + z-index: 99; +} + +.has-navbar { + padding-top: var(--sui-navbar-height); +} + +.has-navbar :target::before { + content: ""; + display: block; + height: 8.5rem; + margin-top: -8.5rem; +} + +.navbar-content { + display: flex; + height: 100%; + width: 100%; + align-items: center; +} + +.navbar-brand { + display: flex; + align-items: center; + margin-right: 4rem; + font-size: 2.5rem; + text-decoration: none; + font-weight: 900; + white-space: nowrap; + line-height: 1em; + background: -webkit-gradient( + linear, + left top, + right top, + from(#cc3721), + color-stop(#f69570), + color-stop(#b024d6), + color-stop(#c42974), + to(#cf2e3e) + ); + background: linear-gradient( + to right, + #cc3721, + #f69570, + #b024d6, + #c42974, + #cf2e3e + ); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +.navbar-logo { + position: relative; + top: 0.25rem; + height: 2.5rem; + width: 2.5rem; + margin: 0 1.25rem 0 0; +} + +.navbar-links { + display: flex; + height: 100%; +} + +.navbar-link { + position: relative; + display: flex; + align-items: center; + padding: 0 1.25rem; + font-size: 1.75rem; + text-decoration: none; + color: inherit; +} + +.navbar-link:hover, +.navbar-link:focus { + color: var(--sui-accent-color-bold, var(--sui-accent-color)); + background: var(--sui-accent-color-background); + outline-size: 1px; + outline-offset: -2px; +} + +.navbar-link.is-active::after { + content: ""; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 0.2rem; + background: var(--sui-accent-color-bold); + box-shadow: 0 0 3px 0 var(--sui-accent-color); +} + +.navbar-search { + margin-left: auto; + flex: 1; + max-width: 30rem; +} + +.sui-theme-picker { + --accent: var(--sui-accent-color-bold); + + padding: 0.75rem; + font-size: 1rem; + cursor: pointer; + outline: none; + background: none; + border: 1px solid var(--accent); + border-radius: 100%; + box-shadow: 0 0 1rem -0.25rem var(--accent), + inset 0 0 1rem -0.75rem var(--accent); + color: var(--accent); + transition: 0.2s; +} + +.sui-theme-picker:focus, +.sui-theme-picker:hover { + box-shadow: 0 0 1rem -0.25rem var(--accent), + inset 0 0 1rem -0.25rem var(--accent); +} + +.navbar-meta-links { + margin-left: 1.5rem; +} + +.navbar-meta-links a { + margin: 0 1.5rem 0 0; + color: var(--sui-color-muted); + text-decoration: none; + font-size: 2.25rem; +} + +.navbar-meta-links a:hover, +.navbar-meta-links a:focus { + color: var(--sui-accent-color-bold, var(--sui-accent-color)); +} + +@media screen and (max-width: 768px) { + .navbar-content { + padding: 0.9rem 0; + } + + .navbar-links { + display: none; + } +} + +@media screen and (max-width: 658px) { + .navbar-brand { + width: 3rem; + margin: -0.5rem 2rem 0 0; + } + + .navbar-logo { + height: auto; + width: 100%; + margin: 0; + } + + .navbar-title { + display: none; + } +} diff --git a/docs-v2/src/doc-components/navbar.js b/docs-v2/src/doc-components/navbar.js new file mode 100644 index 0000000000..70322d081d --- /dev/null +++ b/docs-v2/src/doc-components/navbar.js @@ -0,0 +1,153 @@ +import "./navbar.css" +import React from "react" +import {Link, useStaticQuery, graphql} from "gatsby" +import {Search} from "@standard-ui-docs/search" +import {observer} from "mobx-react" +import {FontAwesomeIcon} from "@fortawesome/react-fontawesome" +import {faSun, faMoon} from "@fortawesome/free-solid-svg-icons" +import {faFile} from "@fortawesome/free-regular-svg-icons" +import {faGithub} from "@fortawesome/free-brands-svg-icons" +import {useStore} from "../store" + +export function Navbar() { + return ( +
    +
    + + + + + +
    +
    + ) +} + +function Brand() { + return ( + + + Stardust UI + + ) +} + +function Links() { + return ( + + ) +} + +function SiteSearch() { + const searchIndex = useSearchIndex() + return ( +
    + +
    + ) +} + +function useSearchIndex() { + const result = useStaticQuery(graphql` + query { + allSitePage { + nodes { + path + context { + frontmatter { + title + description + category + } + } + } + } + } + `) + return React.useMemo(() => { + return result.allSitePage.nodes + .filter( + node => + node.context && + node.context.frontmatter && + node.context.frontmatter.category + ) + .map(node => { + const {title, description, category} = node.context.frontmatter + return { + path: node.path, + category, + title, + description + } + }) + }, [result]) +} + +function MetaLinks() { + return ( + + ) +} + +const ThemePicker = observer(() => { + const store = useStore() + const icon = store.theme === "light" ? faMoon : faSun + return ( + + ) +}) diff --git a/docs-v2/src/doc-components/page-header.css b/docs-v2/src/doc-components/page-header.css new file mode 100644 index 0000000000..f40cfd9d21 --- /dev/null +++ b/docs-v2/src/doc-components/page-header.css @@ -0,0 +1,27 @@ +.sui-page-header { + margin: 4rem 0 2.25rem; + font-size: 1.7rem; + line-height: 2.5rem; +} + +.sui-page-header__title { + margin: 0 0 1rem 0; + max-width: 65rem; + font-size: 2.65em; + line-height: 1.15em; +} + +.sui-page-header__description { + display: block; + max-width: 65rem; + margin: 0; + font-size: 2.15rem; + font-weight: 300; + line-height: 1.35; +} + +@media screen and (max-width: 568px) { + .sui-page-header__title { + margin-bottom: 1.5rem; + } +} diff --git a/docs-v2/src/doc-components/page-header.js b/docs-v2/src/doc-components/page-header.js new file mode 100644 index 0000000000..2460609f09 --- /dev/null +++ b/docs-v2/src/doc-components/page-header.js @@ -0,0 +1,18 @@ +import React from "react" +import {SEO} from "./seo" +import "./page-header.css" + +export function PageHeader({title, description, children}) { + return ( + <> + +
    +

    {title}

    + {description && ( + {description} + )} + {children} +
    + + ) +} diff --git a/docs-v2/src/doc-components/page-nav.css b/docs-v2/src/doc-components/page-nav.css new file mode 100644 index 0000000000..8d019efecb --- /dev/null +++ b/docs-v2/src/doc-components/page-nav.css @@ -0,0 +1,27 @@ +.sui-page-nav { + display: flex; + margin: 2rem 0 4rem; +} + +.sui-page-nav__item { + color: var(--sui-accent-color-bold); + font-size: 1.8rem; + font-weight: 600; + text-decoration: none; +} + +.sui-page-nav__item-label { + display: block; + margin: 0 0 0.5rem 0; + font-weight: 300; + font-size: 0.85em; + color: var(--sui-color-muted); +} + +.sui-page-nav__item.is-next { + margin-left: auto; +} + +.sui-page-nav__item.is-next .sui-page-nav__item-label { + text-align: right; +} diff --git a/docs-v2/src/doc-components/page-nav.js b/docs-v2/src/doc-components/page-nav.js new file mode 100644 index 0000000000..7a8f656863 --- /dev/null +++ b/docs-v2/src/doc-components/page-nav.js @@ -0,0 +1,22 @@ +import "./page-nav.css" +import React from "react" +import {Link} from "gatsby" + +export function PageNav({prev, next}) { + return ( + + ) +} diff --git a/docs-v2/src/doc-components/seo.js b/docs-v2/src/doc-components/seo.js new file mode 100644 index 0000000000..7e3831fd0b --- /dev/null +++ b/docs-v2/src/doc-components/seo.js @@ -0,0 +1,78 @@ +/** + * SEO component that queries for data with + * Gatsby's useStaticQuery React hook + * + * See: https://www.gatsbyjs.org/docs/use-static-query/ + */ + +import React from "react" +import Helmet from "react-helmet" +import {useStaticQuery, graphql} from "gatsby" + +export function SEO({description, lang, meta, title}) { + const {site} = useStaticQuery( + graphql` + query { + site { + siteMetadata { + title + description + author + } + } + } + ` + ) + + const metaDescription = description || site.siteMetadata.description + + return ( + + ) +} + +SEO.defaultProps = { + lang: "en", + meta: [], + description: "" +} diff --git a/docs-v2/src/doc-components/side-nav.css b/docs-v2/src/doc-components/side-nav.css new file mode 100644 index 0000000000..481cdbea16 --- /dev/null +++ b/docs-v2/src/doc-components/side-nav.css @@ -0,0 +1,62 @@ +.sui-side-nav { + --left-gutter-width: 4rem; + + height: 100%; + background: var(--sui-rail-background); + overflow-y: auto; +} + +.sui-side-nav__title { + margin: 2.5rem 0 1.25rem; + padding-left: var(--left-gutter-width); + font-size: 2.5rem; + font-weight: 300; +} + +.sui-side-nav__item { + position: relative; + display: block; + padding: 1rem 0 1rem var(--left-gutter-width); + font-size: 1.65rem; + color: inherit; + text-decoration: none; +} + +.sui-side-nav__item:hover, +.sui-side-nav__item:focus { + cursor: pointer; + color: var(--sui-accent-color-foreground); + background: var(--sui-accent-color-background); +} + +.sui-side-nav__item::before { + content: ""; + position: absolute; + left: 1rem; + top: 40%; + height: 8px; + width: 8px; + background: var(--sui-accent-color-bold); + border-radius: 100%; + transform: scale(0); + transition: 0.2s transform; +} + +.sui-side-nav__item:hover::before { + transform: scale(1); +} + +.sui-side-nav__item.is-active { + color: var(--sui-accent-color-bold); + font-weight: bold; +} + +.sui-side-nav__item.is-active::before { + left: -1rem; + top: 42.5%; + height: 0.75rem; + width: 2.75rem; + border-radius: 0.5rem; + transform: scale(1); + transition: none; +} diff --git a/docs-v2/src/doc-components/side-nav.js b/docs-v2/src/doc-components/side-nav.js new file mode 100644 index 0000000000..6e39ff78db --- /dev/null +++ b/docs-v2/src/doc-components/side-nav.js @@ -0,0 +1,24 @@ +import React from "react" +import {Link} from "gatsby" +import "./side-nav.css" + +export function SideNav({title, links = []}) { + return ( + + ) +} diff --git a/docs-v2/src/examples/accordion/examples/custom-content.js b/docs-v2/src/examples/accordion/examples/custom-content.js new file mode 100644 index 0000000000..912945284d --- /dev/null +++ b/docs-v2/src/examples/accordion/examples/custom-content.js @@ -0,0 +1,23 @@ +import React from "react" +import {Accordion} from "@stardust-ui/react" + +// description: A panel's content can be customized to render any element. +export default ( + + + + + ) + } + } + ]} + /> +) diff --git a/docs-v2/src/examples/accordion/examples/custom-title.js b/docs-v2/src/examples/accordion/examples/custom-title.js new file mode 100644 index 0000000000..4b14b464bc --- /dev/null +++ b/docs-v2/src/examples/accordion/examples/custom-title.js @@ -0,0 +1,29 @@ +import React from "react" +import {Accordion} from "@stardust-ui/react" + +// description: A panel's title can be customized to render any element. +export default ( + } /> + }, + content: { + key: "warnings", + content: "Here is a list of warnings discovered." + } + }, + { + title: { + content: } /> + }, + content: { + key: "errors", + content: "Here is a list of errors discovered." + } + } + ]} + /> +) diff --git a/docs-v2/src/examples/accordion/examples/default.js b/docs-v2/src/examples/accordion/examples/default.js new file mode 100644 index 0000000000..b0ba3efe49 --- /dev/null +++ b/docs-v2/src/examples/accordion/examples/default.js @@ -0,0 +1,21 @@ +import React from "react" +import {Accordion} from "@stardust-ui/react" + +// description: An accordion groups content by a title. Clicking on a title expands that group's content, or closes it if it's already open. +export default ( + +) diff --git a/docs-v2/src/examples/accordion/examples/exclusive.js b/docs-v2/src/examples/accordion/examples/exclusive.js new file mode 100644 index 0000000000..fab7374f05 --- /dev/null +++ b/docs-v2/src/examples/accordion/examples/exclusive.js @@ -0,0 +1,22 @@ +import React from "react" +import {Accordion} from "@stardust-ui/react" + +// description: An exclusive accordion allows only one panel to be open at a time. Opening a panel will close any others that are currently open. +export default ( + +) diff --git a/docs-v2/src/examples/accordion/preview.js b/docs-v2/src/examples/accordion/preview.js new file mode 100644 index 0000000000..6e2be72ad6 --- /dev/null +++ b/docs-v2/src/examples/accordion/preview.js @@ -0,0 +1,17 @@ +export default ( + +) diff --git a/docs-v2/src/examples/alert/examples/action.js b/docs-v2/src/examples/alert/examples/action.js new file mode 100644 index 0000000000..b2f06dc8c4 --- /dev/null +++ b/docs-v2/src/examples/alert/examples/action.js @@ -0,0 +1,10 @@ +import React from "react" +import {Alert} from "@stardust-ui/react" + +// description: An Alert can render an icon to indicate that it's actionable. +export default ( + +) diff --git a/docs-v2/src/examples/alert/examples/attached.js b/docs-v2/src/examples/alert/examples/attached.js new file mode 100644 index 0000000000..59c2162d2e --- /dev/null +++ b/docs-v2/src/examples/alert/examples/attached.js @@ -0,0 +1,10 @@ +import React from "react" +import {Alert} from "@stardust-ui/react" + +// description: An alert can be attached to a nearby element to provide additional information, warnings, or errors. +export default ( +
    + + +
    +) diff --git a/docs-v2/src/examples/alert/examples/danger.js b/docs-v2/src/examples/alert/examples/danger.js new file mode 100644 index 0000000000..be5bfc1eb9 --- /dev/null +++ b/docs-v2/src/examples/alert/examples/danger.js @@ -0,0 +1,5 @@ +import React from "react" +import {Alert} from "@stardust-ui/react" + +// description: A "danger" alert draws attention to an important message, perhaps to inform the user of a mistake or dangerous action. +export default diff --git a/docs-v2/src/examples/alert/examples/default.js b/docs-v2/src/examples/alert/examples/default.js new file mode 100644 index 0000000000..ed9171d185 --- /dev/null +++ b/docs-v2/src/examples/alert/examples/default.js @@ -0,0 +1,5 @@ +import React from "react" +import {Alert} from "@stardust-ui/react" + +// description: The default alert style. +export default diff --git a/docs-v2/src/examples/alert/examples/info.js b/docs-v2/src/examples/alert/examples/info.js new file mode 100644 index 0000000000..70534ceaec --- /dev/null +++ b/docs-v2/src/examples/alert/examples/info.js @@ -0,0 +1,5 @@ +import React from "react" +import {Alert} from "@stardust-ui/react" + +// description: An "info" alert draws attention to additional information about nearby content. +export default diff --git a/docs-v2/src/examples/alert/examples/out-of-office.js b/docs-v2/src/examples/alert/examples/out-of-office.js new file mode 100644 index 0000000000..5c4f1c1854 --- /dev/null +++ b/docs-v2/src/examples/alert/examples/out-of-office.js @@ -0,0 +1,7 @@ +import React from "react" +import {Alert} from "@stardust-ui/react" + +// description: An "out of office" alert is used to indicate that a user unavailable. +export default ( + +) diff --git a/docs-v2/src/examples/alert/examples/success.js b/docs-v2/src/examples/alert/examples/success.js new file mode 100644 index 0000000000..29e374c9e1 --- /dev/null +++ b/docs-v2/src/examples/alert/examples/success.js @@ -0,0 +1,5 @@ +import React from "react" +import {Alert} from "@stardust-ui/react" + +// description: A "success" alert indicates that an event was successful. +export default diff --git a/docs-v2/src/examples/alert/examples/urgent.js b/docs-v2/src/examples/alert/examples/urgent.js new file mode 100644 index 0000000000..72bf5942b6 --- /dev/null +++ b/docs-v2/src/examples/alert/examples/urgent.js @@ -0,0 +1,7 @@ +import React from "react" +import {Alert} from "@stardust-ui/react" + +// description: An "urgent" alert draws extreme attention to a high-priority message. +export default ( + +) diff --git a/docs-v2/src/examples/alert/examples/warning.js b/docs-v2/src/examples/alert/examples/warning.js new file mode 100644 index 0000000000..63061a8842 --- /dev/null +++ b/docs-v2/src/examples/alert/examples/warning.js @@ -0,0 +1,5 @@ +import React from "react" +import {Alert} from "@stardust-ui/react" + +// description: A "warning" alert warns the user, perhaps to prevent common mistakes or indicate a potential problem. +export default diff --git a/docs-v2/src/examples/alert/preview.js b/docs-v2/src/examples/alert/preview.js new file mode 100644 index 0000000000..be32df0e91 --- /dev/null +++ b/docs-v2/src/examples/alert/preview.js @@ -0,0 +1 @@ +export default diff --git a/docs-v2/src/examples/animation/examples/default.js b/docs-v2/src/examples/animation/examples/default.js new file mode 100644 index 0000000000..4437d70455 --- /dev/null +++ b/docs-v2/src/examples/animation/examples/default.js @@ -0,0 +1,35 @@ +import React from "react" +import {Animation} from "@stardust-ui/react" + +// description: +export default ( + + +
    + + +) diff --git a/docs-v2/src/examples/animation/preview.js b/docs-v2/src/examples/animation/preview.js new file mode 100644 index 0000000000..e788185196 --- /dev/null +++ b/docs-v2/src/examples/animation/preview.js @@ -0,0 +1,31 @@ +export default ( + + +
    + + +) diff --git a/docs-v2/src/examples/attachment/examples/action.js b/docs-v2/src/examples/attachment/examples/action.js new file mode 100644 index 0000000000..9f95878317 --- /dev/null +++ b/docs-v2/src/examples/attachment/examples/action.js @@ -0,0 +1,10 @@ +import React from "react" +import {Attachment} from "@stardust-ui/react" + +// description: An attachment can provide the user with an action. +export default ( +
    + + +
    +) diff --git a/docs-v2/src/examples/attachment/examples/default.js b/docs-v2/src/examples/attachment/examples/default.js new file mode 100644 index 0000000000..50d0b363ba --- /dev/null +++ b/docs-v2/src/examples/attachment/examples/default.js @@ -0,0 +1,5 @@ +import React from "react" +import {Attachment} from "@stardust-ui/react" + +// description: The default attachment displays the name of the file. +export default diff --git a/docs-v2/src/examples/attachment/examples/description.js b/docs-v2/src/examples/attachment/examples/description.js new file mode 100644 index 0000000000..b55174245f --- /dev/null +++ b/docs-v2/src/examples/attachment/examples/description.js @@ -0,0 +1,5 @@ +import React from "react" +import {Attachment} from "@stardust-ui/react" + +// description: An attachment can include a description to give more detail about the attachment. +export default diff --git a/docs-v2/src/examples/attachment/examples/icon.js b/docs-v2/src/examples/attachment/examples/icon.js new file mode 100644 index 0000000000..6d73fc7490 --- /dev/null +++ b/docs-v2/src/examples/attachment/examples/icon.js @@ -0,0 +1,11 @@ +import React from "react" +import {Attachment} from "@stardust-ui/react" + +// description: An attachment can include an icon. +export default ( +
    + + + +
    +) diff --git a/docs-v2/src/examples/attachment/examples/progress.js b/docs-v2/src/examples/attachment/examples/progress.js new file mode 100644 index 0000000000..6ee2f8f4ab --- /dev/null +++ b/docs-v2/src/examples/attachment/examples/progress.js @@ -0,0 +1,7 @@ +import React from "react" +import {Attachment} from "@stardust-ui/react" + +// description: An attachment can indicate upload progress. +export default ( + +) diff --git a/docs-v2/src/examples/attachment/preview.js b/docs-v2/src/examples/attachment/preview.js new file mode 100644 index 0000000000..a9dd1c5516 --- /dev/null +++ b/docs-v2/src/examples/attachment/preview.js @@ -0,0 +1 @@ +export default diff --git a/docs-v2/src/examples/avatar/examples/default.js b/docs-v2/src/examples/avatar/examples/default.js new file mode 100644 index 0000000000..852d0d528d --- /dev/null +++ b/docs-v2/src/examples/avatar/examples/default.js @@ -0,0 +1,5 @@ +import React from "react" +import {Avatar} from "@stardust-ui/react" + +// description: The default avatar renders a user's initials. +export default diff --git a/docs-v2/src/examples/avatar/examples/image.js b/docs-v2/src/examples/avatar/examples/image.js new file mode 100644 index 0000000000..88dbf24708 --- /dev/null +++ b/docs-v2/src/examples/avatar/examples/image.js @@ -0,0 +1,5 @@ +import React from "react" +import {Avatar} from "@stardust-ui/react" + +// description: An avatar can show a user's image. +export default diff --git a/docs-v2/src/examples/avatar/examples/sized.js b/docs-v2/src/examples/avatar/examples/sized.js new file mode 100644 index 0000000000..1184935e90 --- /dev/null +++ b/docs-v2/src/examples/avatar/examples/sized.js @@ -0,0 +1,15 @@ +import React from "react" +import {Avatar} from "@stardust-ui/react" + +// description: An avatar can be sized. +export default ( +
    + + + + + + + +
    +) diff --git a/docs-v2/src/examples/avatar/examples/status-border.js b/docs-v2/src/examples/avatar/examples/status-border.js new file mode 100644 index 0000000000..1dd2fba4db --- /dev/null +++ b/docs-v2/src/examples/avatar/examples/status-border.js @@ -0,0 +1,13 @@ +import React from "react" +import {Avatar} from "@stardust-ui/react" + +// description: An avatar's status icon can be bordered. Note, use the "statusBorderColor" theme variable to ensure it matches the background. +export default ( +
    + +
    +) diff --git a/docs-v2/src/examples/avatar/examples/status.js b/docs-v2/src/examples/avatar/examples/status.js new file mode 100644 index 0000000000..8a3809a8af --- /dev/null +++ b/docs-v2/src/examples/avatar/examples/status.js @@ -0,0 +1,10 @@ +import React from "react" +import {Avatar} from "@stardust-ui/react" + +// description: An avatar can show a user's status. +export default ( + +) diff --git a/docs-v2/src/examples/avatar/preview.js b/docs-v2/src/examples/avatar/preview.js new file mode 100644 index 0000000000..f1dc050245 --- /dev/null +++ b/docs-v2/src/examples/avatar/preview.js @@ -0,0 +1,8 @@ +export default ( + +) diff --git a/docs-v2/src/examples/button/examples/circular.js b/docs-v2/src/examples/button/examples/circular.js new file mode 100644 index 0000000000..8ac7324c6a --- /dev/null +++ b/docs-v2/src/examples/button/examples/circular.js @@ -0,0 +1,5 @@ +import React from "react" +import {Button} from "@stardust-ui/react" + +// description: A button can be made circular. This is most often used when the button contains only an icon. +export default diff --git a/docs-v2/src/examples/button/examples/fluid.js b/docs-v2/src/examples/button/examples/fluid.js new file mode 100644 index 0000000000..b2230f7c85 --- /dev/null +++ b/docs-v2/src/examples/button/examples/fluid.js @@ -0,0 +1,5 @@ +import React from "react" +import {Button} from "@stardust-ui/react" + +// description: A fluid button takes up the full width of its container. +export default diff --git a/docs-v2/src/examples/button/examples/grouped.js b/docs-v2/src/examples/button/examples/grouped.js new file mode 100644 index 0000000000..8f13108a6f --- /dev/null +++ b/docs-v2/src/examples/button/examples/grouped.js @@ -0,0 +1,10 @@ +import React from "react" +import {Button} from "@stardust-ui/react" + +// description: Multiple buttons can be grouped together. +export default ( + + diff --git a/docs-v2/src/examples/button/examples/secondary.js b/docs-v2/src/examples/button/examples/secondary.js new file mode 100644 index 0000000000..83f319ab48 --- /dev/null +++ b/docs-v2/src/examples/button/examples/secondary.js @@ -0,0 +1,5 @@ +import React from "react" +import {Button} from "@stardust-ui/react" + +// description: A secondary button emphasizes the secondary action a user is expected to perform. +export default diff --git a/docs-v2/src/examples/button/preview.js b/docs-v2/src/examples/button/preview.js new file mode 100644 index 0000000000..63f8df5cb4 --- /dev/null +++ b/docs-v2/src/examples/button/preview.js @@ -0,0 +1 @@ +export default diff --git a/docs-v2/src/examples/chat/examples/actions.js b/docs-v2/src/examples/chat/examples/actions.js new file mode 100644 index 0000000000..77971a951a --- /dev/null +++ b/docs-v2/src/examples/chat/examples/actions.js @@ -0,0 +1,73 @@ +import React from "react" +import {Chat} from "@stardust-ui/react" + +// description: A chat message can show actions when it is hovered or focused. +const actionMenu = { + iconOnly: true, + items: [ + { + key: "like", + icon: "like", + title: "Like" + }, + { + key: "more", + icon: "more", + title: "More actions" + } + ] +} +const items = [ + { + attached: "top", + contentPosition: "end", + message: { + content: ( + + ) + }, + key: "message-1" + }, + { + attached: "bottom", + contentPosition: "end", + key: "message-2", + message: { + content: ( + + ) + } + }, + { + gutter: { + content: + }, + message: { + content: ( + + ) + }, + key: "message-3" + } +] + +export default ( + +) diff --git a/docs-v2/src/examples/chat/examples/default.js b/docs-v2/src/examples/chat/examples/default.js new file mode 100644 index 0000000000..140eb44519 --- /dev/null +++ b/docs-v2/src/examples/chat/examples/default.js @@ -0,0 +1,51 @@ +import React from "react" +import {Chat} from "@stardust-ui/react" + +// description: The default chat style. +export default ( + + ), + contentPosition: "end" + }, + { + key: 2, + children: + }, + { + key: 3, + gutter: , + message: ( + + ) + }, + { + key: 4, + message: ( + + ), + contentPosition: "end" + } + ]} + /> +) diff --git a/docs-v2/src/examples/chat/examples/message-badges.js b/docs-v2/src/examples/chat/examples/message-badges.js new file mode 100644 index 0000000000..ddf996e1ef --- /dev/null +++ b/docs-v2/src/examples/chat/examples/message-badges.js @@ -0,0 +1,44 @@ +import React from "react" +import {Chat} from "@stardust-ui/react" + +// description: A chat can display a badge to indicate special information about the message. +export default ( + + ) + }, + contentPosition: "end" + }, + { + key: 2, + gutter: { + content: + }, + message: { + content: ( + + ) + } + } + ]} + /> +) diff --git a/docs-v2/src/examples/chat/examples/reactions.js b/docs-v2/src/examples/chat/examples/reactions.js new file mode 100644 index 0000000000..f660e5bf15 --- /dev/null +++ b/docs-v2/src/examples/chat/examples/reactions.js @@ -0,0 +1,60 @@ +import React from "react" +import {Chat} from "@stardust-ui/react" + +// description: A chat message can render reactions from other users. +const LIKED = {key: "like", icon: "like", content: 5} +const SMILED = {key: "emoji", icon: "emoji", content: 2} +const items = [ + { + key: 1, + attached: "top", + contentPosition: "end", + message: { + content: ( + + ) + } + }, + { + key: 2, + attached: "bottom", + contentPosition: "end", + message: { + content: ( + + ) + } + }, + { + key: 3, + gutter: { + content: + }, + message: { + content: ( + + ) + } + } +] + +export default ( + +) diff --git a/docs-v2/src/examples/chat/preview.js b/docs-v2/src/examples/chat/preview.js new file mode 100644 index 0000000000..d455431496 --- /dev/null +++ b/docs-v2/src/examples/chat/preview.js @@ -0,0 +1,13 @@ +export default ( + , + message: ( + + ) + } + ]} + /> +) diff --git a/docs-v2/src/examples/checkbox/examples/checked.js b/docs-v2/src/examples/checkbox/examples/checked.js new file mode 100644 index 0000000000..b21a1aeb9a --- /dev/null +++ b/docs-v2/src/examples/checkbox/examples/checked.js @@ -0,0 +1,5 @@ +import React from "react" +import {Checkbox} from "@stardust-ui/react" + +// description: A checkbox can be forcibly checked or unchecked. +export default diff --git a/docs-v2/src/examples/checkbox/examples/default.js b/docs-v2/src/examples/checkbox/examples/default.js new file mode 100644 index 0000000000..adaf6206cc --- /dev/null +++ b/docs-v2/src/examples/checkbox/examples/default.js @@ -0,0 +1,5 @@ +import React from "react" +import {Checkbox} from "@stardust-ui/react" + +// description: The default checkbox style. +export default diff --git a/docs-v2/src/examples/checkbox/examples/disabled.js b/docs-v2/src/examples/checkbox/examples/disabled.js new file mode 100644 index 0000000000..5928a25bea --- /dev/null +++ b/docs-v2/src/examples/checkbox/examples/disabled.js @@ -0,0 +1,5 @@ +import React from "react" +import {Checkbox} from "@stardust-ui/react" + +// description: A checkbox can be disabled to prevent user interaction. +export default diff --git a/docs-v2/src/examples/checkbox/examples/positioned-label.js b/docs-v2/src/examples/checkbox/examples/positioned-label.js new file mode 100644 index 0000000000..d799353e1c --- /dev/null +++ b/docs-v2/src/examples/checkbox/examples/positioned-label.js @@ -0,0 +1,5 @@ +import React from "react" +import {Checkbox} from "@stardust-ui/react" + +// description: A checkbox's label can be positioned at either the "start" (default) or "end" of the checkbox input. +export default diff --git a/docs-v2/src/examples/checkbox/examples/toggle.js b/docs-v2/src/examples/checkbox/examples/toggle.js new file mode 100644 index 0000000000..10477d880f --- /dev/null +++ b/docs-v2/src/examples/checkbox/examples/toggle.js @@ -0,0 +1,5 @@ +import React from "react" +import {Checkbox} from "@stardust-ui/react" + +// description: A checkbox can be styled to look like a toggle switch. +export default diff --git a/docs-v2/src/examples/checkbox/preview.js b/docs-v2/src/examples/checkbox/preview.js new file mode 100644 index 0000000000..b43ca154f1 --- /dev/null +++ b/docs-v2/src/examples/checkbox/preview.js @@ -0,0 +1 @@ +export default diff --git a/docs-v2/src/examples/dialog/examples/confirmation.js b/docs-v2/src/examples/dialog/examples/confirmation.js new file mode 100644 index 0000000000..740ddd884e --- /dev/null +++ b/docs-v2/src/examples/dialog/examples/confirmation.js @@ -0,0 +1,12 @@ +import React from "react" +import {Dialog} from "@stardust-ui/react" + +// description: A dialog can be used to easily confirm or cancel an operation. +export default ( + } + /> +) diff --git a/docs-v2/src/examples/dialog/examples/content.js b/docs-v2/src/examples/dialog/examples/content.js new file mode 100644 index 0000000000..63df05db3d --- /dev/null +++ b/docs-v2/src/examples/dialog/examples/content.js @@ -0,0 +1,11 @@ +import React from "react" +import {Dialog} from "@stardust-ui/react" + +// description: A dialog's content can be customized to render any element. +export default ( + } + trigger={
    , +
    + 2 +
    , +
    + 3 +
    + ]} + /> +) diff --git a/docs-v2/src/examples/header/examples/alignment.js b/docs-v2/src/examples/header/examples/alignment.js new file mode 100644 index 0000000000..6b2a7fcfcb --- /dev/null +++ b/docs-v2/src/examples/header/examples/alignment.js @@ -0,0 +1,11 @@ +import React from "react" +import {Header} from "@stardust-ui/react" + +// description: A header's content can be aligned "left" (default), "center", or "right". +export default ( +
    +
    +
    +
    +
    +) diff --git a/docs-v2/src/examples/header/examples/colors.js b/docs-v2/src/examples/header/examples/colors.js new file mode 100644 index 0000000000..68e94f558d --- /dev/null +++ b/docs-v2/src/examples/header/examples/colors.js @@ -0,0 +1,12 @@ +import React from "react" +import {Header} from "@stardust-ui/react" + +// description: A header can be colored. +export default ( +
    +
    +
    +
    +
    +
    +) diff --git a/docs-v2/src/examples/header/examples/default.js b/docs-v2/src/examples/header/examples/default.js new file mode 100644 index 0000000000..8924f67007 --- /dev/null +++ b/docs-v2/src/examples/header/examples/default.js @@ -0,0 +1,13 @@ +import React from "react" +import {Header} from "@stardust-ui/react" + +// description: A ramp depicting various headers in their default sizes. +export default ( +
    +
    +
    +
    +
    +
    +
    +) diff --git a/docs-v2/src/examples/header/examples/description.js b/docs-v2/src/examples/header/examples/description.js new file mode 100644 index 0000000000..2600d27e5a --- /dev/null +++ b/docs-v2/src/examples/header/examples/description.js @@ -0,0 +1,11 @@ +import React from "react" +import {Header} from "@stardust-ui/react" + +// description: A header may contain a supplemental description. +export default ( +
    +) diff --git a/docs-v2/src/examples/header/preview.js b/docs-v2/src/examples/header/preview.js new file mode 100644 index 0000000000..1b4b0172cb --- /dev/null +++ b/docs-v2/src/examples/header/preview.js @@ -0,0 +1 @@ +export default
    diff --git a/docs-v2/src/examples/hierarchical-tree/examples/default.js b/docs-v2/src/examples/hierarchical-tree/examples/default.js new file mode 100644 index 0000000000..86be65ede4 --- /dev/null +++ b/docs-v2/src/examples/hierarchical-tree/examples/default.js @@ -0,0 +1,5 @@ +import React from "react" +import {HierarchicalTree} from "@stardust-ui/react" + +// description: The default tree style. +export default undefined diff --git a/docs-v2/src/examples/hierarchical-tree/examples/exclusive.js b/docs-v2/src/examples/hierarchical-tree/examples/exclusive.js new file mode 100644 index 0000000000..827abbf380 --- /dev/null +++ b/docs-v2/src/examples/hierarchical-tree/examples/exclusive.js @@ -0,0 +1,5 @@ +import React from "react" +import {HierarchicalTree} from "@stardust-ui/react" + +// description: An exclusive tree allows only one branch to be open at each level. Opening a collapse branch will automatically close the open one. +export default undefined diff --git a/docs-v2/src/examples/icon/examples/bordered.js b/docs-v2/src/examples/icon/examples/bordered.js new file mode 100644 index 0000000000..7a6fa42439 --- /dev/null +++ b/docs-v2/src/examples/icon/examples/bordered.js @@ -0,0 +1,5 @@ +import React from "react" +import {Icon} from "@stardust-ui/react" + +// description: An icon can render a border around the glyph. +export default diff --git a/docs-v2/src/examples/icon/examples/circular.js b/docs-v2/src/examples/icon/examples/circular.js new file mode 100644 index 0000000000..c1f53b01df --- /dev/null +++ b/docs-v2/src/examples/icon/examples/circular.js @@ -0,0 +1,5 @@ +import React from "react" +import {Icon} from "@stardust-ui/react" + +// description: An icon can be rendered as a circle. +export default diff --git a/docs-v2/src/examples/icon/examples/colors.js b/docs-v2/src/examples/icon/examples/colors.js new file mode 100644 index 0000000000..96bf0f8237 --- /dev/null +++ b/docs-v2/src/examples/icon/examples/colors.js @@ -0,0 +1,33 @@ +import React from "react" +import {Icon} from "@stardust-ui/react" + +// description: An icon can be rendered in a variety of colors. +export default ( + +
    + +
    + pink +
    +
    + +
    + red +
    +
    + +
    + yellow +
    +
    + +
    + orange +
    +
    + +
    + green +
    +
    +) diff --git a/docs-v2/src/examples/icon/examples/default.js b/docs-v2/src/examples/icon/examples/default.js new file mode 100644 index 0000000000..95883a32e8 --- /dev/null +++ b/docs-v2/src/examples/icon/examples/default.js @@ -0,0 +1,5 @@ +import React from "react" +import {Icon} from "@stardust-ui/react" + +// description: The default icon style. +export default diff --git a/docs-v2/src/examples/icon/examples/disabled.js b/docs-v2/src/examples/icon/examples/disabled.js new file mode 100644 index 0000000000..12f4af8f88 --- /dev/null +++ b/docs-v2/src/examples/icon/examples/disabled.js @@ -0,0 +1,5 @@ +import React from "react" +import {Icon} from "@stardust-ui/react" + +// description: An icon can show that it can't be interacted with. +export default diff --git a/docs-v2/src/examples/icon/examples/rotated.js b/docs-v2/src/examples/icon/examples/rotated.js new file mode 100644 index 0000000000..67e937dd8a --- /dev/null +++ b/docs-v2/src/examples/icon/examples/rotated.js @@ -0,0 +1,13 @@ +import React from "react" +import {Icon} from "@stardust-ui/react" + +// description: An icon can be rotated by a specified number of degrees. +export default ( + + + + + + + +) diff --git a/docs-v2/src/examples/icon/examples/sizes.js b/docs-v2/src/examples/icon/examples/sizes.js new file mode 100644 index 0000000000..0b1308513e --- /dev/null +++ b/docs-v2/src/examples/icon/examples/sizes.js @@ -0,0 +1,43 @@ +import React from "react" +import {Icon} from "@stardust-ui/react" + +// description: An icon can be made to smaller or larger than its default size. +export default ( + +
    + +
    + smallest +
    +
    + +
    + smaller +
    +
    + +
    + small +
    +
    + +
    + default +
    +
    + +
    + large +
    +
    + +
    + larger +
    +
    + +
    + largest +
    +
    +) diff --git a/docs-v2/src/examples/icon/preview.js b/docs-v2/src/examples/icon/preview.js new file mode 100644 index 0000000000..5168a65751 --- /dev/null +++ b/docs-v2/src/examples/icon/preview.js @@ -0,0 +1 @@ +export default diff --git a/docs-v2/src/examples/image/preview.js b/docs-v2/src/examples/image/preview.js new file mode 100644 index 0000000000..91bc2203d6 --- /dev/null +++ b/docs-v2/src/examples/image/preview.js @@ -0,0 +1 @@ +export default diff --git a/docs-v2/src/examples/input/examples/clearable.js b/docs-v2/src/examples/input/examples/clearable.js new file mode 100644 index 0000000000..7db2c1705b --- /dev/null +++ b/docs-v2/src/examples/input/examples/clearable.js @@ -0,0 +1,5 @@ +import React from "react" +import {Input} from "@stardust-ui/react" + +// description: A clearable input renders an "X" that allows a user to clear the input's current value. +export default diff --git a/docs-v2/src/examples/input/examples/default-value.js b/docs-v2/src/examples/input/examples/default-value.js new file mode 100644 index 0000000000..71f86ef3ee --- /dev/null +++ b/docs-v2/src/examples/input/examples/default-value.js @@ -0,0 +1,5 @@ +import React from "react" +import {Input} from "@stardust-ui/react" + +// description: An input can be configured to start with a default value. +export default diff --git a/docs-v2/src/examples/input/examples/default.js b/docs-v2/src/examples/input/examples/default.js new file mode 100644 index 0000000000..73933f6dd8 --- /dev/null +++ b/docs-v2/src/examples/input/examples/default.js @@ -0,0 +1,5 @@ +import React from "react" +import {Input} from "@stardust-ui/react" + +// description: The default input style. +export default diff --git a/docs-v2/src/examples/input/examples/fluid.js b/docs-v2/src/examples/input/examples/fluid.js new file mode 100644 index 0000000000..28764949aa --- /dev/null +++ b/docs-v2/src/examples/input/examples/fluid.js @@ -0,0 +1,5 @@ +import React from "react" +import {Input} from "@stardust-ui/react" + +// description: An input can take up the full width of its container. +export default diff --git a/docs-v2/src/examples/input/examples/icon.js b/docs-v2/src/examples/input/examples/icon.js new file mode 100644 index 0000000000..071271d099 --- /dev/null +++ b/docs-v2/src/examples/input/examples/icon.js @@ -0,0 +1,5 @@ +import React from "react" +import {Input} from "@stardust-ui/react" + +// description: An input can render an icon. +export default diff --git a/docs-v2/src/examples/input/examples/inline.js b/docs-v2/src/examples/input/examples/inline.js new file mode 100644 index 0000000000..3b6acd2918 --- /dev/null +++ b/docs-v2/src/examples/input/examples/inline.js @@ -0,0 +1,11 @@ +import React from "react" +import {Input} from "@stardust-ui/react" + +// description: An input can be rendered in-line with other content. +export default ( + <> + There's an inline input + + inside of this content + +) diff --git a/docs-v2/src/examples/input/examples/positioned-icon.js b/docs-v2/src/examples/input/examples/positioned-icon.js new file mode 100644 index 0000000000..53e7b2413b --- /dev/null +++ b/docs-v2/src/examples/input/examples/positioned-icon.js @@ -0,0 +1,7 @@ +import React from "react" +import {Input} from "@stardust-ui/react" + +// description: An input's icon can be positioned at the "start" or "end" (default) of the input. +export default ( + +) diff --git a/docs-v2/src/examples/input/preview.js b/docs-v2/src/examples/input/preview.js new file mode 100644 index 0000000000..3b75edf371 --- /dev/null +++ b/docs-v2/src/examples/input/preview.js @@ -0,0 +1 @@ +export default diff --git a/docs-v2/src/examples/label/preview.js b/docs-v2/src/examples/label/preview.js new file mode 100644 index 0000000000..6feb08deff --- /dev/null +++ b/docs-v2/src/examples/label/preview.js @@ -0,0 +1 @@ +export default