Merge pull request 'development' (#1) from development into main

Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
2025-11-05 02:45:48 +05:30
60 changed files with 1484 additions and 565 deletions

321
.gitignore vendored
View File

@@ -46,3 +46,324 @@ backlog.yml
Lottie Structure.txt
LottieSchema.json
.hintrc
# Component Modules built for local dev using lerna should be ignored
AboutUs
Accordion
AdvancedColorPicker
Alert
AlertStackManager
AlphabetFilter
Anchor
AppAndToolsSelector
Application
ArIconsViewer
ArViz
ArmcoIamProvider
Badge
Banner
Benefits
Blog
Brands
Breadcrumb
Breadcrumbs
BrowserIncompatibility
BubbleChart
BubbleViz
Button
Card
Careers
Carousel
CategoryFilter
Checkbox
Chunk
ColorPicker
ColorPickerConfig
ColorSelector
Component_404
Contact
Content
ContextMenu
Cookies
CronTab
Cta
Dashboard
DateInput
DetailsPanel
Dialog
Download
Draggable
Drawer
Dropdown
Droppable
DroppableContainer
EcommOrders
EcommProducts
Empty
ErrorBoundary
FacetedFilter
Faq
Features
Filters
FlexTools
Footer
Form
Gallery
Graph
GraphTiles
Header
Hero
HowItWorks
HttpCode
Image
InlineMenu
InstaPhotos
Integrations
Label
LabelValue
LayoutGenerator
LearnLink
Link
List
ListItem
Loader
LoginProvider
LogoClouds
Main
Mask
MenuButton
Modal
Newsletter
Notification
Notifications
NumericStepper
Pagination
Password
PickerRange
Picklist
Pill
Pillbox
Popover
PopoverV1
PopoverV2
Portal
Portfolio
Pricing
ProductDescriptionTile
ProductInfo
ProgressIndicator
ProgressStepper
ProgressiveBarChart
Projects
Radio
RepeatRenderer
Reviews
ScrollPagination
SearchField
SecondaryNavigation
Segment
SegmentedControl
Select
SelectionPill
Services
SidePanel
SignInUp
Slider
Snackbar
Splitter
Stats
Steps
StuffleIamProvider
Suggestions
Swiper
Tab
TabBar
Table
Tag
Tags
Team
Testimonials
Text
TextArea
TextInput
Thumbs
Tiles
TimeEntry
Toast
Toggle
Toolbar
Tooltip
TransferShuttle
TreeList
TreeViz
TypeAhead
UserOptions
Users
Widget
Wizard
WizardModal
animations
ass
cssClasses
index
Waiting for the debugger to disconnect...
Debugger attached.
AboutUs
Accordion
AdvancedColorPicker
Alert
AlertStackManager
AlphabetFilter
Anchor
AppAndToolsSelector
Application
ArIconsViewer
ArViz
ArmcoIamProvider
Badge
Banner
Benefits
Blog
Brands
Breadcrumb
Breadcrumbs
BrowserIncompatibility
BubbleChart
BubbleViz
Button
Card
Careers
Carousel
CategoryFilter
Checkbox
Chunk
ColorPicker
ColorPickerConfig
ColorSelector
Component_404
Contact
Content
ContextMenu
Cookies
CronTab
Cta
Dashboard
DateInput
DetailsPanel
Dialog
Download
Draggable
Drawer
Dropdown
Droppable
DroppableContainer
EcommOrders
EcommProducts
Empty
ErrorBoundary
FacetedFilter
Faq
Features
Filters
FlexTools
Footer
Form
Gallery
Graph
GraphTiles
Header
Hero
HowItWorks
HttpCode
Image
InlineMenu
InstaPhotos
Integrations
Label
LabelValue
LayoutGenerator
LearnLink
Link
List
ListItem
Loader
LoginProvider
LogoClouds
Main
Mask
MenuButton
Modal
Newsletter
Notification
Notifications
NumericStepper
Pagination
Password
PickerRange
Picklist
Pill
Pillbox
Popover
PopoverV1
PopoverV2
Portal
Portfolio
Pricing
ProductDescriptionTile
ProductInfo
ProgressIndicator
ProgressStepper
ProgressiveBarChart
Projects
Radio
RepeatRenderer
Reviews
ScrollPagination
SearchField
SecondaryNavigation
Segment
SegmentedControl
Select
SelectionPill
Services
SidePanel
SignInUp
Slider
Snackbar
Splitter
Stats
Steps
StuffleIamProvider
Suggestions
Swiper
Tab
TabBar
Table
Tag
Tags
Team
Testimonials
Text
TextArea
TextInput
Thumbs
Tiles
TimeEntry
Toast
Toggle
Toolbar
Tooltip
TransferShuttle
TreeList
TypeAhead
UserOptions
Users
Widget
Wizard
WizardModal
animations
ass
cssClasses
index

6
TreeViz/package.json Normal file
View File

@@ -0,0 +1,6 @@
{
"name": "@armco/components/TreeViz",
"main": "../build/cjs/TreeViz.js",
"module": "../build/es/TreeViz.js",
"types": "../build/types/TreeViz.d.ts"
}

View File

@@ -3,10 +3,34 @@
# Get the directory of the current script
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
rm -rf build
npx tsc
vite build
# Default values
DEV_FLAG=""
# Parse arguments
for arg in "$@"
do
case $arg in
--dev)
DEV_FLAG="--dev"
shift # Remove --dev from processing
;;
esac
done
echo "[BUILD:SH] Dev flag is: $DEV_FLAG"
echo "[BUILD:SH] Removing build if exists"
rm -rf build
echo "[BUILD:SH] Checking TS Types"
npx tsc
echo "[BUILD:SH] Initiating build..."
# Conditionally use vite-dev.config.ts if --dev flag is present
if [ "$DEV_FLAG" == "--dev" ]; then
vite build --config vite-dev.config.ts
else
vite build
fi
echo "[BUILD:SH] Running post processor scripts..."
# Run Post processors: Update style imports in .js files, create component modules
node "$SCRIPT_DIR/post-processor.js" build/cjs
node "$SCRIPT_DIR/post-processor.js" build/es
node "$SCRIPT_DIR/post-processor.js" build/cjs $DEV_FLAG
node "$SCRIPT_DIR/post-processor.js" build/es $DEV_FLAG

View File

@@ -5,17 +5,17 @@ import { fileURLToPath } from "url"
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
async function generateModule(fileName, parentDir) {
if (fileName.indexOf("-chunk") === -1) {
async function generateModule(fileName, isDev) {
if (fileName.indexOf("-chunk") === -1 && !fileName.endsWith(".map")) {
const dir = fileName.slice(0, -3)
const name = `@armco/components/${dir}`
const packageJsonContent = {
name,
main: `../cjs/${dir}.js`,
module: `../es/${dir}.js`,
types: `../types/${dir}.d.ts`,
main: `../${isDev ? "build/" : ""}cjs/${dir}.js`,
module: `../${isDev ? "build/" : ""}es/${dir}.js`,
types: `../${isDev ? "build/" : ""}types/${dir}.d.ts`,
}
const dirPath = resolve(__dirname, `../build/${dir}`)
const dirPath = resolve(__dirname, `../${isDev ? "" : "build/"}${dir}`)
try {
await fs.mkdir(dirPath, { recursive: true })
await fs.writeFile(

View File

@@ -1,13 +1,13 @@
import { readdir } from "fs/promises"
import generateModule from "./generate-module.js"
async function postProcessor(dir) {
async function postProcessor(dir, isDev) {
try {
const files = await readdir(dir)
await Promise.all(
files.map(async (file) => {
// await fixStyles(file, dir)
await generateModule(file, dir)
await generateModule(file, isDev)
}),
)
} catch (error) {
@@ -17,7 +17,7 @@ async function postProcessor(dir) {
const targetDir = process.argv[2]
if (targetDir) {
postProcessor(targetDir)
postProcessor(targetDir, process.argv.includes("--dev"))
} else {
console.error("Please provide the build directory to run post processor on.")
process.exit(1)

View File

@@ -1,7 +1,7 @@
{
"name": "@armco/shared-components",
"description": "React Component Lib of independent components that can be utilised by sophisticated ones in @armco/components",
"version": "0.0.53",
"version": "0.0.57",
"type": "module",
"author": "Armco (@restruct-corporate-advantage)",
"types": "build/types/index.d.ts",
@@ -9,6 +9,7 @@
"module": "build/es/index.js",
"scripts": {
"build": "./build-tools/build.sh",
"build:sm": "./build-tools/build.sh --dev",
"plop": "plop component",
"format": "prettier --write .",
"lint": "eslint .",
@@ -18,92 +19,34 @@
"publish:local": "./publish-local.sh"
},
"dependencies": {
"@armco/configs": "^0.0.6",
"@armco/icon": "^0.0.5",
"@armco/utils": "^0.0.16",
"@popperjs/core": "^2.11.8",
"@armco/configs": "^0.0.11",
"@armco/utils": "^0.0.29",
"@armco/icon": "^0.0.10",
"@tanstack/react-table": "^8.21.2",
"bootstrap": "^5.3.0",
"classnames": "^2.3.2",
"d3": "^7.9.0",
"highcharts": "^11.2.0",
"highcharts-react-official": "^3.2.1",
"highlight.js": "^11.8.0",
"js-cookie": "^3.0.5",
"moment": "^2.29.4",
"react-app-polyfill": "^3.0.0",
"react-bootstrap": "^2.7.4",
"react-dev-utils": "^12.0.1",
"react": ">=16.8.0",
"react-bootstrap": "^2.7.4",
"react-dnd": ">=16.0.0",
"react-dnd-html5-backend": ">=16.0.0",
"react-dnd-touch-backend": ">=16.0.0",
"react-dom": "^18.2.0",
"react-draggable": "^4.4.6",
"react-redux": "^8.0.1",
"resize-observer-polyfill": "^1.5.1",
"react-resizable": "^3.0.5",
"react-router-dom": "^6.13.0",
"react-table": "^7.8.0",
"resize-observer-polyfill": "^1.5.1",
"svgpath": "^2.6.0",
"uuid": "^9.0.0"
},
"devDependencies": {
"@armco/types": "^0.0.11",
"@babel/preset-env": "^7.24.5",
"@babel/preset-react": "^7.24.1",
"@babel/preset-typescript": "^7.24.1",
"@testing-library/dom": "^9.2.0",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.2.5",
"@types/bootstrap": "^5.2.6",
"@types/d3": "^7.4.0",
"@types/js-cookie": "^3.0.3",
"@types/node": "^22.5.5",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.2.18",
"@types/react-resizable": "^3.0.7",
"@types/react-table": "^7.7.19",
"@types/testing-library__jest-dom": "^5.14.5",
"@types/uuid": "^9.0.2",
"@vitejs/plugin-react": "^4.3.1",
"chalk": "^5.3.0",
"cherry-pick": "^0.5.0",
"cpy-cli": "^5.0.0",
"eslint": "^8.0.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-storybook": "^0.6.12",
"execa": "^8.0.1",
"fs-extra": "^11.2.0",
"glob": "^10.4.5",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jsdom": "^21.1.0",
"plop": "^3.1.2",
"prettier": "^2.7.1",
"prettier-config-nick": "^1.0.2",
"prop-types": "^15.8.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"rollup-plugin-visualizer": "^5.12.0",
"sass-embedded": "^1.79.3",
"storybook": "^7.0.23",
"ts-jest": "^29.2.3",
"ts-node": "^10.9.2",
"typescript": "^5.0.2",
"vite": "^5.4.7",
"vite-plugin-css-injected-by-js": "^3.5.1",
"vite-plugin-dts": "^4.2.1",
"vite-plugin-lib-inject-css": "^2.1.1",
"vite-plugin-svgr": "^4.2.0",
"vitest": "^2.1.1"
"@armco/types": "^0.0.18"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dnd": ">=16.0.0",
"react-dnd-html5-backend": ">=16.0.0",
"react-dnd-touch-backend": ">=16.0.0",
"react-redux": "^8.0.1",
"react-router-dom": "^6.13.0"
"d3": "^7.9.0",
"highcharts": "^12.1.2",
"highcharts-react-official": "^3.2.1",
"highlight.js": "^11.8.0",
"moment": "^2.29.4",
},
"eslintConfig": {
"extends": [

View File

@@ -11,251 +11,26 @@ module.exports = (plop) => {
actions: [
{
type: "add",
path: "src/app/components/{{pascalCase name}}/{{pascalCase name}}.tsx",
path: "src/{{pascalCase name}}.tsx",
templateFile: "plop-templates/Component/Component.tsx.hbs",
},
{
type: "add",
path: "src/app/components/{{pascalCase name}}/{{pascalCase name}}.test.ts",
templateFile: "plop-templates/Component/Component.test.ts.hbs",
},
{
type: "add",
path: "src/app/components/{{pascalCase name}}/{{pascalCase name}}.component.scss",
path: "src/{{pascalCase name}}.component.scss",
templateFile: "plop-templates/Component/Component.component.scss.hbs",
},
{
type: "add",
path: "src/app/components/{{pascalCase name}}/index.ts",
templateFile: "plop-templates/Component/index.ts.hbs",
},
{
type: "add",
path: "src/app/components/index.ts",
path: "src/index.ts",
templateFile: "plop-templates/injectable-index.ts.hbs",
skipIfExists: true,
},
{
type: "append",
path: "src/app/components/index.ts",
path: "src/index.ts",
pattern: `/* PLOP_INJECT_IMPORT */`,
template: `import {{pascalCase name}} from "./{{pascalCase name}}"`,
},
{
type: "append",
path: "src/app/components/index.ts",
pattern: `/* PLOP_INJECT_EXPORT */`,
template: ` {{pascalCase name}},`,
},
{
type: "append",
path: "src/app/components/index.ts",
pattern: `/* PLOP_INJECT_TYPE_IMPORT */`,
template: ` {{pascalCase name}}Props,`,
},
{
type: "append",
path: "src/app/components/index.ts",
pattern: `/* PLOP_INJECT_TYPE_EXPORT */`,
template: ` type {{pascalCase name}}Props,`,
},
{
type: "append",
path: "src/app/types/components.interface.ts",
pattern: `/* PLOP_INJECT_INTERFACE */`,
template: `export interface {{pascalCase name}}Props extends BaseProps {\n}\n`,
},
],
})
plop.setGenerator("atom", {
description: "Create a component",
prompts: [
{
type: "input",
name: "name",
message: "What is your component name?",
},
],
actions: [
{
type: "add",
path: "src/app/components/{{pascalCase name}}/{{pascalCase name}}.tsx",
templateFile: "plop-templates/Component/Component.tsx.hbs",
},
{
type: "add",
path: "src/app/components/{{pascalCase name}}/{{pascalCase name}}.test.ts",
templateFile: "plop-templates/Component/Component.test.ts.hbs",
},
{
type: "add",
path: "src/app/components/{{pascalCase name}}/{{pascalCase name}}.component.scss",
templateFile: "plop-templates/Component/Component.component.scss.hbs",
},
{
type: "add",
path: "src/app/components/{{pascalCase name}}/index.ts",
templateFile: "plop-templates/Component/index.ts.hbs",
},
{
type: "add",
path: "src/app/components/index.ts",
templateFile: "plop-templates/injectable-index.ts.hbs",
skipIfExists: true,
},
{
type: "append",
path: "src/app/components/index.ts",
pattern: `/* PLOP_INJECT_IMPORT */`,
template: `import {{pascalCase name}} from "./{{pascalCase name}}"`,
},
{
type: "append",
path: "src/app/components/index.ts",
pattern: `/* PLOP_INJECT_EXPORT */`,
template: ` {{pascalCase name}},`,
},
{
type: "append",
path: "src/app/components/index.ts",
pattern: `/* PLOP_INJECT_TYPE_IMPORT */`,
template: ` {{pascalCase name}}Props,`,
},
{
type: "append",
path: "src/app/components/index.ts",
pattern: `/* PLOP_INJECT_TYPE_EXPORT */`,
template: ` type {{pascalCase name}}Props,`,
},
{
type: "append",
path: "src/app/types/components.interface.ts",
pattern: `/* PLOP_INJECT_INTERFACE */`,
template: `export interface {{pascalCase name}}Props extends BaseProps {\n}\n`,
},
],
})
plop.setGenerator("molecule", {
description: "Create a rich component",
prompts: [
{
type: "input",
name: "name",
message: "What is your component name?",
},
],
actions: [
{
type: "add",
path: "src/app/components/{{pascalCase name}}/{{pascalCase name}}.tsx",
templateFile: "plop-templates/Component/Component.tsx.hbs",
},
{
type: "add",
path: "src/app/components/{{pascalCase name}}/{{pascalCase name}}.test.ts",
templateFile: "plop-templates/Component/Component.test.ts.hbs",
},
{
type: "add",
path: "src/app/components/{{pascalCase name}}/{{pascalCase name}}.component.scss",
templateFile: "plop-templates/Component/Component.component.scss.hbs",
},
{
type: "add",
path: "src/app/components/{{pascalCase name}}/index.ts",
templateFile: "plop-templates/Component/index.ts.hbs",
},
{
type: "add",
path: "src/app/components/index.ts",
templateFile: "plop-templates/injectable-index.ts.hbs",
skipIfExists: true,
},
{
type: "append",
path: "src/app/components/index.ts",
pattern: `/* PLOP_INJECT_IMPORT */`,
template: `import {{pascalCase name}} from "./{{pascalCase name}}"`,
},
{
type: "append",
path: "src/app/components/index.ts",
pattern: `/* PLOP_INJECT_EXPORT */`,
template: ` {{pascalCase name}},`,
},
{
type: "append",
path: "src/app/components/index.ts",
pattern: `/* PLOP_INJECT_TYPE_IMPORT */`,
template: ` {{pascalCase name}}Props,`,
},
{
type: "append",
path: "src/app/components/index.ts",
pattern: `/* PLOP_INJECT_TYPE_EXPORT */`,
template: ` type {{pascalCase name}}Props,`,
},
{
type: "append",
path: "src/app/types/components.interface.ts",
pattern: `/* PLOP_INJECT_INTERFACE */`,
template: `export interface {{pascalCase name}}Props extends BaseProps {\n}\n`,
},
],
})
plop.setGenerator("page", {
description: "Create a page",
prompts: [
{
type: "input",
name: "name",
message: "What is your page name?",
},
],
actions: [
{
type: "add",
path: "src/app/pages/{{pascalCase name}}/{{pascalCase name}}.tsx",
templateFile: "plop-templates/Page/Page.tsx.hbs",
},
{
type: "add",
path: "src/app/pages/{{pascalCase name}}/{{pascalCase name}}.test.ts",
templateFile: "plop-templates/Page/Page.test.ts.hbs",
},
{
type: "add",
path: "src/app/pages/{{pascalCase name}}/{{pascalCase name}}.page.scss",
templateFile: "plop-templates/Page/Page.page.scss.hbs",
},
{
type: "add",
path: "src/app/pages/{{pascalCase name}}/index.ts",
templateFile: "plop-templates/Page/index.ts.hbs",
},
{
type: "add",
path: "src/app/pages/{{pascalCase name}}/{{pascalCase name}}.slice.ts",
templateFile: "plop-templates/Page/Page.slice.ts.hbs",
},
{
type: "add",
path: "src/app/pages/index.ts",
templateFile: "plop-templates/injectable-index.ts.hbs",
skipIfExists: true,
},
{
type: "append",
path: "src/app/pages/index.ts",
pattern: `/* PLOP_INJECT_IMPORT */`,
template: `import {{pascalCase name}} from "./{{pascalCase name}}"`,
},
{
type: "append",
path: "src/app/pages/index.ts",
pattern: `/* PLOP_INJECT_EXPORT */`,
template: ` {{pascalCase name}},`,
},
template: `export { default as {{pascalCase name}} } from "./{{pascalCase name}}"`,
}
],
})
}

View File

@@ -29,12 +29,12 @@ const AdvancedColorPicker = (props: AdvancedColorPickerProps): JSX.Element => {
saturation !== undefined &&
lightness !== undefined
? "hsl(" +
Math.round(hue * 255) +
", " +
Math.round(saturation * 100) +
"%, " +
Math.round(lightness * 100) +
"%)"
Math.round(hue * 255) +
", " +
Math.round(saturation * 100) +
"%, " +
Math.round(lightness * 100) +
"%)"
: ""
}
@@ -45,7 +45,11 @@ const AdvancedColorPicker = (props: AdvancedColorPickerProps): JSX.Element => {
)}
<img
className="flex-h-center"
src="https://static.armco.tech/secure/file/raw/6ec65585-052f-4004-b664-4bd4e2617040"
src={
process.env.NODE_ENV === "production"
? "https://static.armco.dev/file/raw/6ec65585-052f-4004-b664-4bd4e2617040"
: "http://localhost:5001/api/file/raw/ffb4eb66-47ec-427f-aa9e-30bcc2116c57"
}
useMap={`#colormap-${id}`}
alt={`colormap-${id}`}
/>

View File

@@ -26,10 +26,12 @@ const AppTile = (props: AppTileProps) => {
size: "2rem",
colors: {
fillColor: theme === ArThemes.LIGHT1 ? "#777" : "#bbb",
strokeColor: theme === ArThemes.LIGHT1 ? "#777" : "#bbb",
hoverFillColor: theme === ArThemes.LIGHT1 ? "black" : "white",
},
}}
icon={icon}
fillPath
/>
<span className="ar-AppTile__name">{label}</span>
</div>

View File

@@ -1,5 +1,6 @@
.ar-ArIconsViewer {
grid-template-columns: minmax(10rem, 1fr);
color: #0b8dfa;
.ar-ScrollPagination__items-container.compact, .ar-ScrollPagination__items-container.comfy {
.ar-ArIconsViewer__icon-container:hover {

View File

@@ -21,7 +21,7 @@ import Tooltip from "./Tooltip"
import "./ArIconsViewer.component.scss"
const pageApi =
STATIC_HOST[process.env.NODE_ENV as "development" | "production"] +
STATIC_HOST[process.env.NODE_ENV] +
ENDPOINTS.STATIC.ICON.ROOT +
ENDPOINTS.STATIC.ICON.PAGE

View File

@@ -1,6 +1,7 @@
import { v4 as uuid } from "uuid"
import { ArThemes, BrowserIncompatibilityProps } from "@armco/types"
import { copyToClipboard } from "@armco/utils/helper"
import { useTheme } from "@armco/utils/hooks"
import Icon from "@armco/icon"
import Alert from "./Alert"
import Link from "./Link"
@@ -9,7 +10,8 @@ import "./BrowserIncompatibility.component.scss"
const BrowserIncompatibility = (
props: BrowserIncompatibilityProps,
): JSX.Element => {
const { applicationName, moreLink, theme } = props
const { applicationName, moreLink } = props
const { theme } = useTheme()
const demoDummyLink = "https://notabuck.com/armco-design-system/docs/devices"
const demoAppName = '"My Awesome App"'
const helpLink = moreLink || demoDummyLink

View File

@@ -1,11 +1,9 @@
import { useEffect, useRef } from "react"
import Highcharts from "highcharts"
import HighchartsMore from "highcharts/highcharts-more"
import "highcharts/highcharts-more"
import { BubbleChartProps, ObjectType } from "@armco/types"
import "./BubbleChart.component.scss"
HighchartsMore(Highcharts)
const BubbleChart = (props: BubbleChartProps): JSX.Element => {
const { clickHandler, data } = props
const chartRef = useRef(null)

View File

@@ -13,7 +13,6 @@ const Button = (props: ButtonProps) => {
const {
classes,
color,
containerClasses,
contentClasses,
contentStyles,
content,
@@ -45,7 +44,7 @@ const Button = (props: ButtonProps) => {
variant === ArButtonVariants.LINK ||
variant === ArButtonVariants.LINKHOVEREFFECT
) {
setColor = "black"
setColor = theme === ArThemes.DARK1 ? "white" : "black"
} else if (variant === ArButtonVariants.SECONDARY) {
setColor = hovered
? theme === ArThemes.DARK1
@@ -81,7 +80,9 @@ const Button = (props: ButtonProps) => {
{...rest}
>
{preIcon && (
<span className={`ar-Button__icon pre${content ? " me-2" : ""}`}>
<span
className={`ar-Button__icon flex-center pre${content ? " me-2" : ""}`}
>
<Icon
icon={preIcon}
attributes={{ colors: { fillColor: setColor } }}
@@ -93,7 +94,11 @@ const Button = (props: ButtonProps) => {
(!preIcon && !postIcon ? "Button" : "")}
</span>
{postIcon && (
<span className={`ar-Button__icon post${content ? " ms-2" : ""}`}>
<span
className={`ar-Button__icon flex-center post${
content ? " ms-2" : ""
}`}
>
<Icon
icon={postIcon}
attributes={{ colors: { fillColor: setColor } }}

View File

@@ -122,7 +122,11 @@ export default class Carousel extends Component<CarouselProps, CarouselState> {
item &&
(
Children.toArray(
(item as React.ReactElement).props.children,
(
(item as React.ReactElement).props as {
children: ReactNode
}
).children,
) as ReactNode[]
).find(
(children) => (children as React.ReactElement).type === "img",

View File

@@ -9,6 +9,7 @@ import {
} from "react"
import { findDOMNode } from "react-dom"
import { useDrag } from "react-dnd"
import { getEmptyImage } from "react-dnd-html5-backend"
import { ArDndItemTypes, DraggableProps } from "@armco/types"
import "./Draggable.component.scss"
@@ -22,7 +23,7 @@ const Draggable = forwardRef((props: DraggableProps, ref) => {
const {
canDrag,
children,
demo,
hideDefaultPreview,
itemData,
itemType = ArDndItemTypes.GENERIC,
style,
@@ -30,12 +31,11 @@ const Draggable = forwardRef((props: DraggableProps, ref) => {
const localRef = useRef(null)
ref = ref || localRef
const useChildren = demo ? children || dummyChildren : children
let firstChild
if (typeof useChildren === "string") {
firstChild = <span>{useChildren}</span>
if (typeof children === "string") {
firstChild = <span>{children}</span>
} else {
const childrenArray = Children.toArray(useChildren)
const childrenArray = Children.toArray(children)
firstChild = childrenArray[0]
// Warn if more than one child is passed
if (childrenArray.length > 1) {
@@ -45,7 +45,7 @@ const Draggable = forwardRef((props: DraggableProps, ref) => {
}
}
const [{ isDragging }, drag] = useDrag(
const [{ isDragging }, drag, preview] = useDrag(
() => ({
type: itemType,
item: itemData,
@@ -64,6 +64,12 @@ const Draggable = forwardRef((props: DraggableProps, ref) => {
}
}, [drag])
useEffect(() => {
if (hideDefaultPreview && preview) {
preview(getEmptyImage(), { captureDraggingState: true })
}
}, [hideDefaultPreview, preview])
const {
style: childStyles,
className: childClasses,

View File

@@ -1,5 +1,12 @@
.ar-Drawer {
border-right: 1px solid var(--ar-color-layout-border);
.ar_Drawer__content {
height: 100%;
}
&.has-title .ar-Drawer__content {
height: calc(100% - 0.875rem - 2rem - 1px) // -font-size - padding - border
}
&.collapsed {
.ar-Drawer__expander {
right: 1rem;

View File

@@ -9,7 +9,7 @@ const isMobile = checkMobile()
let clickedSelf: boolean
const Drawer = (props: DrawerProps): JSX.Element => {
const { children, classes, isCollapsible } = props
const { children, classes, contentClasses, isCollapsible, title } = props
const drawerRef = useRef<HTMLDivElement>(null)
const { drawerState, setDrawerState } = useDrawerState()
const { theme } = useTheme()
@@ -25,9 +25,11 @@ const Drawer = (props: DrawerProps): JSX.Element => {
return (
<aside
className={`ar-Drawer overflow-auto${classes ? " " + classes : ""}${
isCollapsible ? " position-relative" : ""
}${drawerState?.collapsed ? " collapsed" : ""}`}
className={`ar-Drawer overflow-auto d-flex flex-column${
classes ? " " + classes : ""
}${isCollapsible ? " position-relative" : ""}${
drawerState?.collapsed ? " collapsed" : ""
}${title ? " has-title" : ""}`}
tabIndex={-1}
ref={drawerRef}
onMouseDown={() => {
@@ -44,24 +46,37 @@ const Drawer = (props: DrawerProps): JSX.Element => {
>
{isCollapsible && (
<Icon
attributes={{
classes:
"ar-Drawer__expander position-absolute cursor-pointer d-none d-sm-inline z-1",
colors: { fillColor: theme === ArThemes.DARK1 ? "white" : "black" },
size: "1.5rem",
}}
icon={
drawerState?.collapsed
? "tb/TbLayoutSidebarLeftExpand"
: "tb/TbLayoutSidebarLeftCollapse"
}
attributes={{
classes:
"ar-Drawer__expander position-absolute cursor-pointer d-none d-sm-inline",
colors: {
strokeColor: theme === ArThemes.DARK1 ? "white" : "black",
},
size: "1.5rem",
}}
events={{
onClick: () =>
setDrawerState({ collapsed: !drawerState?.collapsed }),
}}
/>
)}
{!drawerState?.collapsed && children}
{title && !drawerState?.collapsed && (
<div className="ar-Drawer__title p-3 fw-bold f35 border-bottom">
{title}
</div>
)}
<div
className={`ar-Drawer__content${
contentClasses ? " " + contentClasses : ""
}`}
>
{!drawerState?.collapsed && children}
</div>
</aside>
)
}

View File

@@ -165,7 +165,9 @@ const Dropdown = (props: DropdownProps): JSX.Element => {
)
const assistiveContentRender = assistiveContent ? (
"content" in assistiveContent && "onClick" in assistiveContent ? (
typeof assistiveContent === "object" &&
"content" in assistiveContent &&
"onClick" in assistiveContent ? (
<Button
classes="mb-2 p-0 f3"
variant={ArButtonVariants.LINK}

View File

@@ -6,7 +6,6 @@ import {
ArDndItemTypes,
ArLoaderTypes,
DroppableContainerProps,
SlotDescriptor,
TreeListData,
} from "@armco/types"
import Icon from "@armco/icon"
@@ -53,7 +52,7 @@ const DroppableContainer = (props: DroppableContainerProps): JSX.Element => {
}
}, [placeholder, placeholderType, placeholderProps])
const dropHandler = (sourceData: SlotDescriptor | TreeListData | any) => {
const dropHandler = (sourceData: { label: string } | TreeListData | any) => {
let componentName = sourceData.label
if (!componentName) {
componentName = sourceData.componentName

View File

@@ -1,4 +1,5 @@
.ar-FlexTools {
max-height: 4rem;
.col {
border-right: var(--ar-border);
}

View File

@@ -28,7 +28,7 @@ const userOptions = [
const isMobile = checkMobile()
const FlexTools = (props: FlexToolsProps): JSX.Element => {
const { isLanding, route } = props
const { isLanding, route, hideAppLogo, onLogout } = props
const { theme } = useTheme()
const navigate = useNavigate()
@@ -82,14 +82,19 @@ const FlexTools = (props: FlexToolsProps): JSX.Element => {
const userOps = (
<UserOptions
classes={`h-100 flex-center px-2${isLanding ? " ms-auto" : ""}`}
loginProvider={ArLoginProviders.ARMCO}
loginProvider={ArLoginProviders.IAM}
options={userOptions}
onLogout={onLogout}
isLanding={isLanding}
theme={theme}
/>
)
return (
<div className="ar-FlexTools h-100 flex-center w-100">
<div
className={`ar-FlexTools h-100 w-100 ${
hideAppLogo ? "flex-v-center justify-content-end" : "flex-center"
}`}
>
{!isMobile ? (
<>
{appSelector}
@@ -97,18 +102,30 @@ const FlexTools = (props: FlexToolsProps): JSX.Element => {
{userOps}
</>
) : (
<div className="row w-100">
<div className="col flex-center" onClick={() => navigate("/")}>
<span className="ar-FlexTools__app-name h-100 flex-center">
Stuffle.
<span className="ar-FlexTools__app-name-i">i</span>
<span className="ar-FlexTools__app-name-o">o</span>
</span>
</div>
<div className="ar-FlexTools__app-selector col flex-center">
<div
className={`w-100${
hideAppLogo ? " d-flex justify-content-end" : " row"
}`}
>
{!hideAppLogo && (
<div className="col flex-center" onClick={() => navigate("/")}>
<span className="ar-FlexTools__app-name h-100 flex-center">
Stuffle.
<span className="ar-FlexTools__app-name-i">i</span>
<span className="ar-FlexTools__app-name-o">o</span>
</span>
</div>
)}
<div
className={`ar-FlexTools__app-selector flex-center${
hideAppLogo ? "" : " col"
}`}
>
{appSelector}
</div>
<div className="col flex-center">{userOps}</div>
<div className={`flex-center${hideAppLogo ? "" : " col"}`}>
{userOps}
</div>
</div>
)}
</div>

View File

@@ -1,32 +1,39 @@
import { ArThemes } from "@armco/types"
import { ArThemes, FooterProps } from "@armco/types"
import { useSlotted, useTheme } from "@armco/utils/hooks"
import { isMobile as checkMobile } from "@armco/utils/helper"
import Icon from "@armco/icon"
import FlexTools from "./FlexTools"
import Toggle from "./Toggle"
import "./Footer.component.scss"
interface FooterProps {}
const isMobile = checkMobile()
const Footer = (props: FooterProps): JSX.Element => {
const Footer = ({ onThemeToggle }: FooterProps): JSX.Element => {
const { theme, setTheme } = useTheme()
useSlotted("Footer")
return (
<footer className="ar-Footer w-100 d-flex py-1">
{!isMobile ? (
<Toggle
classes="ms-auto"
isOn={theme === ArThemes.DARK1}
toggleOffName="Go Dark"
toggleOnName="Go Dark"
onChange={(isChecked: boolean) => {
const nextTheme = isChecked ? ArThemes.DARK1 : ArThemes.LIGHT1
setTheme(nextTheme)
document
.getElementsByTagName("html")[0]
.setAttribute("ar-theme", nextTheme)
<Icon
icon="cg.CgDarkMode"
attributes={{
classes: "d-sm-inline d-none ms-auto",
height: "2.5rem",
width: "1.5rem",
colors: {
fillColor: theme === ArThemes.DARK1 ? "lightgrey" : "black",
},
}}
events={{
onClick: () => {
const nextTheme =
theme === ArThemes.LIGHT1 ? ArThemes.DARK1 : ArThemes.LIGHT1
setTheme(nextTheme)
document
.getElementsByTagName("html")[0]
.setAttribute("ar-theme", nextTheme)
onThemeToggle && onThemeToggle(nextTheme)
},
}}
/>
) : (

View File

@@ -31,7 +31,7 @@ const Hero = (props: HeroProps): JSX.Element => {
<div className="ar-Hero__image w-50">
<img
className="w-100"
src="https://static.armco.tech/secure/file/raw/4dc03aa6-3467-4ddc-9789-5d68ff2782d6"
src="https://static.armco.dev/file/raw/4dc03aa6-3467-4ddc-9789-5d68ff2782d6"
alt="Component Lib"
/>
</div>

View File

@@ -10,7 +10,7 @@ const getDomainFromUrl = (url: string) => {
// Function to determine crossOrigin value
const determineCrossOrigin = (url: string) => {
const domain = getDomainFromUrl(url)
if (domain === "localhost" || domain === "armco.tech") {
if (domain === "localhost" || domain === "armco.dev") {
return "use-credentials"
}
return "anonymous"

View File

@@ -49,6 +49,14 @@
background-color: var(--ar-color-highlight-2);
color: var(--ar-color-hover);
}
&:hover {
background-color: var(--ar-color-font);
color: var(--ar-color-font-invert);
cursor: pointer;
.ar-Button {
color: var(--ar-color-font-invert) !important;
}
}
}
&:not(.with-check-boxes) {
.ar-List__item.is-selected {

View File

@@ -1,6 +1,7 @@
import { useEffect, useState } from "react"
import { v4 as uuid } from "uuid"
import { ArListStyles, ListItemContent, ListProps } from "@armco/types"
import { ListItem } from "./ListItem"
import ListItem from "./ListItem"
import "./List.component.scss"
const dummyData = [
@@ -17,25 +18,28 @@ const List = (props: ListProps): JSX.Element => {
isRaw,
classes,
data,
demo,
invertBg,
isMultiSelect,
itemClasses,
itemRenderer,
itemVariant = "dynamic",
onItemClick,
showCheckBoxes,
style,
theme,
variant,
} = props
let root
const useData = data || (demo && dummyData)
const [localItems, setLocalItems] = useState<Array<ListItemContent>>()
const [selected, setSelected] = useState<ListItemContent>()
useEffect(() => {
setLocalItems(useData)
}, [useData])
data && setLocalItems(data.map(item => {
if (!Array.isArray(item) && !item.uid) {
item.uid = uuid()
}
return item
}))
}, [data])
const getListItem = (item: ListItemContent, index: string) => {
if (Array.isArray(item)) {
@@ -64,11 +68,11 @@ const List = (props: ListProps): JSX.Element => {
itemRenderer={itemRenderer}
itemVariant={itemVariant}
key={"list-child-" + index}
onClick={onItemClick}
selected={selected}
setItems={setLocalItems}
setSelected={setSelected}
showCheckBoxes={showCheckBoxes}
theme={theme}
variant={variant}
/>
)

View File

@@ -1,3 +1,4 @@
import { memo, useEffect, useState } from "react"
import {
ArButtonVariants,
ArListVariants,
@@ -8,32 +9,33 @@ import {
ObjectType,
} from "@armco/types"
import { search } from "@armco/utils/helper"
import { useTheme } from "@armco/utils/hooks"
import Icon from "@armco/icon"
import Button from "./Button"
import { memo, useEffect, useState } from "react"
export const ListItem = memo((props: ListItemProps) => {
const ListItem = memo((props: ListItemProps) => {
const {
actions,
index,
isMultiSelect,
isRaw,
item,
item = {},
items,
itemClasses,
itemRenderer,
itemVariant,
onClick,
selected,
setItems,
setSelected,
showCheckBoxes,
theme,
variant,
} = props
const { label, name, color, preIcon, postIcon } = !Array.isArray(item)
const { label, name, color, preIcon, postIcon, uid } = !Array.isArray(item)
? item
: { label: "", preIcon: "", postIcon: "", name: "", color: "" }
const [isSelected, setLocalSelected] = useState<boolean>()
const { theme } = useTheme()
useEffect(() => {
!Array.isArray(item) && setLocalSelected(item.isSelected)
@@ -52,7 +54,7 @@ export const ListItem = memo((props: ListItemProps) => {
? isSelected
: !Array.isArray(selected) &&
!Array.isArray(item) &&
(selected?.name || selected?.label) === (name || label)
(selected?.uid || selected?.name || selected?.label) === (uid || name || label)
)
? " is-selected"
: ""
@@ -74,9 +76,10 @@ export const ListItem = memo((props: ListItemProps) => {
searchedItem.isSelected = !searchedItem.isSelected
setItems(itemsClone)
}
} else {
} else if (setSelected) {
setSelected(item)
}
onClick && onClick(item, items)
!Array.isArray(item) &&
item.onClick &&
(item.onClick as FunctionType)(item, items)
@@ -91,8 +94,8 @@ export const ListItem = memo((props: ListItemProps) => {
? item.isSelected
? "io5.IoCheckmarkCircleOutline"
: "io.IoIosRadioButtonOff"
: (item.name || item.label) ===
(selected?.name || selected?.label)
: (item.uid || item.name || item.label) ===
(selected?.uid || selected?.name || selected?.label)
? "io.IoIosRadioButtonOn"
: "io.IoIosRadioButtonOff"
: ""
@@ -119,7 +122,8 @@ export const ListItem = memo((props: ListItemProps) => {
variant={ArButtonVariants.LINK}
content={!Array.isArray(item) ? label || name : ""}
size={ArSizes.XSMALL}
color={color}
theme={theme}
color={color || theme === ArThemes.DARK1 ? "#aaa" : "#676767"}
/>
) : !Array.isArray(item) ? (
label || name
@@ -132,11 +136,11 @@ export const ListItem = memo((props: ListItemProps) => {
<Icon icon={postIcon} attributes={{ colors: { fillColor: color } }} />
)}
{actions && actions.length > 0 && (
<div className="ms-auto border-left">
<div className="ms-auto border-left ps-2">
{actions?.map((actionItem, index) => (
<Icon
key={`list-action-item-${
!Array.isArray(item) ? label || name : ""
!Array.isArray(item) ? uid || label || name : ""
}-${index}`}
icon={actionItem.icon}
attributes={{
@@ -148,7 +152,7 @@ export const ListItem = memo((props: ListItemProps) => {
classes: `hover-bg ${index > 0 ? "ms-1" : ""}`,
}}
events={{
onClick: () => actionItem.action(item),
onClick: (e) => actionItem.action(item, e),
}}
/>
))}
@@ -157,3 +161,5 @@ export const ListItem = memo((props: ListItemProps) => {
</li>
)
})
export default ListItem

View File

@@ -37,7 +37,7 @@ const Loader = (props: LoaderProps): JSX.Element => {
icon={
icon || {
source:
"https://static.armco.tech/secure/file/raw/f6cf8ba7-e836-464e-9237-4726fea0af47",
"https://static.armco.dev/file/raw/f6cf8ba7-e836-464e-9237-4726fea0af47",
type: ArIconSourceTypes.URL,
}
}
@@ -83,14 +83,16 @@ const Loader = (props: LoaderProps): JSX.Element => {
return (
<div
className={`position-absolute ar-Loader h-100 w-100${
className={`position-absolute ar-Loader top-0 start-0 h-100 w-100${
classes ? " " + classes : ""
}`}
>
<div
className={`ar-Loader-content flex-center w-100 h-100${
type ? " " + type : ""
}${size ? " " + size : ""}`}
}${size ? " " + size : ""}${
type !== ArLoaderTypes.SHAPES ? " flex-column" : ""
}`}
>
{loaderContent}
</div>

View File

@@ -1,3 +1,3 @@
.ar-LoginProvider {
width: 30rem;
min-width: 25rem;
}

View File

@@ -10,9 +10,7 @@ const LoginProvider = (props: LoginProviderProps): JSX.Element => {
return (
<div className="ar-LoginProvider position-relative h-100">
<iframe
src={
url || IAMCLIENT[process.env.NODE_ENV as "development" | "production"]
}
src={url || IAMCLIENT[process.env.NODE_ENV]}
title="IAM"
className="ar-LoginProvider__frame h-100 w-100"
/>
@@ -21,7 +19,7 @@ const LoginProvider = (props: LoginProviderProps): JSX.Element => {
size={ArSizes.SMALL}
classes="position-absolute top-0 end-0"
content="Close"
onClick={() => setRightPanelContent({ name: "" })}
onClick={() => setRightPanelContent({ componentName: "" })}
/>
</div>
)

View File

@@ -1,7 +1,8 @@
.ar-Main {
.ar-Drawer {
transition: width 0.3s;
width: 15%;
min-width: 15%;
max-width: 20%;
&.collapsed {
width: 3.5rem;
}

View File

@@ -1,4 +1,5 @@
import { ArPlacement, MainProps } from "@armco/types"
import { usePanelContent } from "@armco/utils/hooks"
import ErrorBoundary from "./ErrorBoundary"
import SidePanel from "./SidePanel"
import Content from "./Content"
@@ -7,34 +8,50 @@ import "./Main.component.scss"
const Main = (props: MainProps): JSX.Element => {
const {
classes,
contentClasses,
drawerContent,
drawerTitle,
mainContent,
hideSidepanelCloseButton,
rightPanelContent,
leftPanelContent,
rightPanelHeader,
leftPanelHeader,
} = props
const { panelContent: leftPanelContent } = usePanelContent(true)
const { panelContent: rightPanelContent } = usePanelContent(false)
return (
<main className="ar-Main d-flex flex-grow-1 w-100">
<main
className={`ar-Main d-flex flex-grow-1 w-100${
classes ? " " + classes : ""
}`}
>
{drawerContent && (
<Drawer classes="d-flex h-100" isCollapsible>
<Drawer
classes="d-flex h-100"
title={drawerTitle}
contentClasses="p-2"
isCollapsible
>
{drawerContent}
</Drawer>
)}
<SidePanel
key="left-panel"
header={leftPanelHeader || "Header Name"}
classes={
leftPanelContent?.componentName ? "miw-20" : "miw-0 overflow-hidden"
}
header={leftPanelHeader}
placement={ArPlacement.LEFT}
componentName={leftPanelContent ? leftPanelContent.name : ""}
componentProps={leftPanelContent ? leftPanelContent.props : {}}
componentName={leftPanelContent ? leftPanelContent.componentName : ""}
componentProps={leftPanelContent ? leftPanelContent.componentProps : {}}
component={leftPanelContent ? leftPanelContent.component : null}
hideCloseButton={hideSidepanelCloseButton}
/>
<ErrorBoundary>
<Content
classes={`flex-center flex-grow-1 position-relative overflow-auto${
classes={`flex-center position-relative overflow-auto${
contentClasses ? " " + contentClasses : ""
}`}
>
@@ -44,8 +61,10 @@ const Main = (props: MainProps): JSX.Element => {
<SidePanel
key="right-panel"
header={rightPanelHeader}
componentName={rightPanelContent ? rightPanelContent.name : ""}
componentProps={rightPanelContent ? rightPanelContent.props : {}}
componentName={rightPanelContent ? rightPanelContent.componentName : ""}
componentProps={
rightPanelContent ? rightPanelContent.componentProps : {}
}
component={rightPanelContent ? rightPanelContent.component : null}
hideCloseButton={hideSidepanelCloseButton}
/>

View File

@@ -5,9 +5,10 @@ import {
ArPopoverPositions,
ArPopoverSlots,
ArPopoverTriggers,
ArSizes,
ArThemes,
ListItemContent,
MenuButtonProps,
MenuButtonProps,
} from "@armco/types"
import Icon from "@armco/icon"
import List from "./List"
@@ -24,15 +25,16 @@ const demoSplitOptions: Array<ListItemContent> = [
const MenuButton = (props: MenuButtonProps) => {
const {
buttonProps,
containerClasses,
demo,
classes,
demo,
splitButtonClasses,
splitOptions,
splitPopoverVersion,
splitTrigger,
theme,
} = props
const { color, disabled, variant, content, preIcon, postIcon, size } = buttonProps || {}
const { color, disabled, variant, content, preIcon, postIcon, size = ArSizes.SMALL } =
buttonProps || {}
const [hovered, setHovered] = useState<boolean>()
const useSplitOptions = demo
? typeof splitOptions === "string" && splitOptions === "true"
@@ -71,17 +73,15 @@ const MenuButton = (props: MenuButtonProps) => {
return (
<div
className={`d-inline-flex${
containerClasses ? " " + containerClasses : ""
}`}
onMouseEnter={(e) => {
setHovered(true)
}}
onMouseLeave={(e) => {
setHovered(false)
}}
className={`d-inline-flex${classes ? " " + classes : ""}`}
onMouseEnter={(e) => {
setHovered(true)
}}
onMouseLeave={(e) => {
setHovered(false)
}}
>
{hasButton && <Button withSplitOptions />}
{hasButton && <Button {...buttonProps} withSplitOptions />}
{useSplitOptions && (
<Popover
trigger={splitTrigger || ArPopoverTriggers.CLICK}

View File

@@ -58,9 +58,6 @@
&.transition {
transition: width 0.15s ease-in-out, height 0.15s ease-in-out, opacity 0.3s ease-in-out, transform 0.15s ease-in-out;
// &.bottom {
// transform: translateX(-10%);
// }
&.expand-shrink {
transform: scale(0.8);
}
@@ -68,18 +65,5 @@
transform: scale(1);
}
}
@media (min-width: 576px) {
max-width: 25vw;
}
}
.ar-List__item {
line-height: 1.5rem;
&:hover {
background-color: var(--ar-color-font);
color: var(--ar-color-font-invert);
cursor: pointer;
}
}
}

View File

@@ -49,7 +49,6 @@ const PopoverV2 = (props: PopoverProps): JSX.Element => {
closeOnSelfClick,
contentClasses,
contentMatchAnchorWidth,
demo,
disabled,
hideMarker,
invertBg,
@@ -109,14 +108,12 @@ const PopoverV2 = (props: PopoverProps): JSX.Element => {
popAtPointer && trigger === ArPopoverTriggers.CLICK
? clickCoordinatesRef.current
: null,
demo,
topOffset,
)
setPopoverLeftTop(leftTop)
setPopoverPosition(usePosition)
}, [
contentMatchAnchorWidth,
demo,
hideMarker,
popAtPointer,
position,
@@ -158,17 +155,7 @@ const PopoverV2 = (props: PopoverProps): JSX.Element => {
if (trigger === ArPopoverTriggers.CLICK && popoverVisible) {
document.addEventListener("mousedown", listener)
const iframe = document.querySelector("iframe")
if (iframe) {
iframe.contentWindow?.document.addEventListener("mousedown", listener)
}
return () => {
document.removeEventListener("click", listener)
const iframe = document.querySelector("iframe")
if (iframe) {
iframe.contentWindow?.document.removeEventListener("click", listener)
}
}
return () => document.removeEventListener("click", listener)
}
}, [trigger, popoverVisible, onClose])
@@ -288,7 +275,6 @@ const PopoverV2 = (props: PopoverProps): JSX.Element => {
classes={`position-fixed popover-container${
popoverVisible ? " z-3000" : " invisible"
}`}
demo={demo}
styles={popoverLeftTop || {}}
>
<div

View File

@@ -1,11 +1,10 @@
import { useEffect, useState } from "react"
import ReactDOM from "react-dom"
import { PortalProps } from "@armco/types"
import { getDocumentElement } from "@armco/utils/domHelper"
import "./Portal.component.scss"
const Portal = (props: PortalProps) => {
const { children, classes, container, demo, styles } = props
const { children, classes, container, styles } = props
const [portal, setPortal] = useState<HTMLElement | null>()
useEffect(() => {
@@ -15,23 +14,18 @@ const Portal = (props: PortalProps) => {
useEffect(() => {
if (portal) {
const doc = getDocumentElement(demo)
if (doc) {
const root = doc.getElementById("root")
if (root) {
root.appendChild(portal as HTMLElement)
}
const root = document.getElementById("root")
if (root) {
root.appendChild(portal as HTMLElement)
}
return () => {
if (doc) {
const root = doc.getElementById("root")
if (root) {
root.removeChild(portal as HTMLElement)
}
const root = document.getElementById("root")
if (root) {
root.removeChild(portal as HTMLElement)
}
}
}
}, [portal, demo])
}, [portal])
useEffect(() => {
if (portal) {

View File

@@ -6,6 +6,8 @@ import { adaptToProgressiveChart } from "@armco/utils/adapters"
import Icon from "@armco/icon"
import "./ProgressiveBarChart.component.scss"
const HighchartsReactComp = HighchartsReact as any
const ProgressiveBarChart = (props: ProgressiveBarChartProps): JSX.Element => {
const {
data,
@@ -133,7 +135,7 @@ const ProgressiveBarChart = (props: ProgressiveBarChartProps): JSX.Element => {
/>
</div>
</div>
<HighchartsReact highcharts={Highcharts} options={chartOptions} />
<HighchartsReactComp highcharts={Highcharts} options={chartOptions} />
</div>
)
}

View File

@@ -2,23 +2,18 @@ import { MutableRefObject, useEffect, useRef, useState } from "react"
import { v4 as uuid } from "uuid"
import { FunctionType, ObjectType, ScrollPaginationProps } from "@armco/types"
import { get } from "@armco/utils/network"
import { getWindowElement, getDocumentElement } from "@armco/utils/domHelper"
import Icon from "@armco/icon"
import "./ScrollPagination.component.scss"
function isElementInViewport(el: HTMLElement, demo?: boolean): boolean {
const rect = el.getBoundingClientRect()
const windowObj = getWindowElement(demo)
const documentObj = getDocumentElement(demo)
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <=
(windowObj?.innerHeight ||
documentObj?.documentElement.clientHeight ||
0) &&
(window.innerHeight || document.documentElement.clientHeight || 0) &&
rect.right <=
(windowObj?.innerWidth || documentObj?.documentElement.clientWidth || 0)
(window.innerWidth || document.documentElement.clientWidth || 0)
)
}

View File

@@ -39,9 +39,9 @@ const SidePanel = memo((props: SidePanelProps): JSX.Element | null => {
: !placement || placement === ArPlacement.RIGHT
? "right"
: "left"
return component || (componentName && SelectedComponent) ? (
return component || SelectedComponent ? (
<div
className={`ar-SidePanel h-100 d-flex flex-column overflow-auto${
className={`ar-SidePanel h-100 d-flex flex-column${
isFloating ? " floating position-absolute top-0" : " position-relative"
}${" " + placementClass}${componentName ? " " + componentName : ""}${
classes ? " " + classes : ""
@@ -63,7 +63,7 @@ const SidePanel = memo((props: SidePanelProps): JSX.Element | null => {
content="Close"
classes="position-absolute top-0 end-0"
variant={ArButtonVariants.LINK}
onClick={() => setRightPanelContent({ name: "" })}
onClick={() => setRightPanelContent({ componentName: "" })}
/>
)}
</>

View File

@@ -17,6 +17,10 @@
// background-color: var(--ar-bg-selected);
}
&.compact {
max-height: 2rem;
}
&.minimal {
&:hover {
color: var(--ar-color-secondary);

View File

@@ -35,14 +35,12 @@ const Tab = memo(
// Wrap with a setTimeout to delay calculation of tab bounds
// since tab bounds change after icons are added from API
setTimeout(() => {
const selectedTabDimensions =
tabRef.current && tabRef.current.getBoundingClientRect()
let selectedWidth, selectedLeft
if (selectedTabDimensions) {
selectedWidth = selectedTabDimensions.width
selectedLeft = tabRef.current.offsetLeft
if (tabRef.current) {
const selectedTabDimensions = tabRef.current.getBoundingClientRect()
const selectedWidth = selectedTabDimensions.width
const selectedLeft = tabRef.current.offsetLeft
bubbleDimensions(selectedWidth, selectedLeft)
}
bubbleDimensions(selectedWidth, selectedLeft)
}, 0)
}
}, [isActive, bubbleDimensions])

View File

@@ -15,6 +15,10 @@
}
}
&.compact {
height: 2rem;
}
&.minimal {
height: 2rem;
font-size: 0.7rem;

View File

@@ -34,7 +34,7 @@ const TabBar = (props: TabBarProps): JSX.Element => {
theme,
...rest
} = props
const [activeTab, setActiveTabASync] = useState<ObjectType>()
const [activeTab, setActiveTabAsync] = useState<ObjectType>()
const [hoveredTab, setHoveredTab] = useState<{
data: TabProps
element: Element
@@ -44,7 +44,7 @@ const TabBar = (props: TabBarProps): JSX.Element => {
const useData = data || (demo && dummyData)
const setActiveTab = (activeTab: ObjectType) => {
setActiveTabASync((currentActiveTab) =>
setActiveTabAsync((currentActiveTab) =>
activeTab.id === ""
? activeTab
: {

View File

@@ -1,5 +1,11 @@
import { CSSProperties, useMemo } from "react"
import { Column, useTable } from "react-table"
import { CSSProperties, ReactNode, useMemo } from "react"
import {
AccessorFnColumnDef,
AccessorKeyColumnDef,
flexRender,
getCoreRowModel,
useReactTable,
} from "@tanstack/react-table"
import {
ArTableLayouts,
ObjectType,
@@ -8,19 +14,20 @@ import {
} from "@armco/types"
import "./Table.component.scss"
const dummyColumns: Array<Column<TableRowItem>> = [
{ Header: "S. No.", accessor: "sNo" },
const dummyColumns: Array<
| AccessorKeyColumnDef<TableRowItem, any>
| AccessorFnColumnDef<TableRowItem, any>
> = [
{ header: "S. No.", accessorKey: "sNo" },
{
Header: "Name",
accessor: "name",
classes: "text-start ps-3",
style: { width: "7rem" },
} as Column<TableRowItem>,
{ Header: "Description", accessor: "about" },
{ Header: "Type", accessor: "type" },
{ Header: "Status", accessor: "status" },
{ Header: "Assignee", accessor: "assignee" },
{ Header: "Actions" },
header: "Name",
accessorKey: "name",
},
{ header: "Description", accessorKey: "about" },
{ header: "Type", accessorKey: "type" },
{ header: "Status", accessorKey: "status" },
{ header: "Assignee", accessorKey: "assignee" },
{ header: "Actions", accessorKey: "actions" },
]
const dummyData: Array<TableRowItem> = [
@@ -109,11 +116,12 @@ const Table = (props: TableProps) => {
[],
)
const useData = data ? data : demo ? dummyData : []
const { getTableProps, headerGroups, rows, prepareRow } =
useTable<TableRowItem>({
columns: useColumns,
data: useData,
})
const table = useReactTable({
data: useData,
columns: useColumns,
getCoreRowModel: getCoreRowModel(),
})
const layoutConfig: ObjectType =
LAYOUT_CONFIGS[layout || ArTableLayouts.NORMAL]
@@ -125,38 +133,48 @@ const Table = (props: TableProps) => {
layout ? " " + layout : ""
} ${layoutConfig.fontClass as string}`}
>
<table className="w-100 text-center" {...getTableProps()}>
<table className="w-100 text-center">
<thead>
{headerGroups?.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
{table.getHeaderGroups().map((headerGroup) => (
<tr {...headerGroup}>
{headerGroup.headers.map((header) => (
<th
className={`border-bottom ${
layoutConfig.paddingClass as string
}`}
{...column.getHeaderProps()}
{...header}
>
{column.render("Header")}
{
flexRender(
header.column.columnDef.header,
header.getContext(),
) as ReactNode
}
</th>
))}
</tr>
))}
</thead>
<tbody className="overflow-auto">
{rows?.map((row, i) => {
prepareRow(row)
{table.getRowModel().rows?.map((row, i) => {
return (
<tr className="border-bottom" {...row.getRowProps()}>
{row.cells.map((cell) => {
<tr className="border-bottom" {...row}>
{/* {flexRender(cell.column.columnDef.cell, cell.getContext())} */}
{row.getVisibleCells().map((cell) => {
return (
<td
className={`${layoutConfig.paddingClass as string} ${
(cell.column as any).classes as string
}`}
style={(cell.column as any).style as CSSProperties}
{...cell.getCellProps()}
{...cell}
>
{cell.render("Cell")}
{
flexRender(
cell.column.columnDef.cell,
cell.getContext(),
) as ReactNode
}
</td>
)
})}

View File

@@ -4,6 +4,7 @@
--text-shadow: none;
--text-overflow: auto;
--text-animation: scrollText 10s linear infinite;
white-space: pre;
position: relative;
line-height: 1.1rem;
min-height: 1.1rem;

View File

@@ -7,7 +7,6 @@ import {
TextFormat,
TextProps,
} from "@armco/types"
import { getDocumentElement, getWindowElement } from "@armco/utils/domHelper"
import Tooltip from "./Tooltip"
import Chunk from "./Chunk"
import "./Text.component.scss"
@@ -57,9 +56,9 @@ const Text = (props: TextProps): JSX.Element => {
width,
...rest
} = props
const { chunks, cursorPosition, startContainer, id, text } = descriptor
const { chunks, cursorPosition, startContainer, id, text } = descriptor || {}
const [contentEditable, setContentEditable] = useState<boolean>()
const textContentRef = useRef<string | undefined>()
const textContentRef = useRef<string>("")
const textElementRef = useRef<HTMLDivElement | HTMLInputElement>(null)
const [isOverflowing, setIsOverflowing] = useState<boolean>()
const [animationDuration, setAnimationDuration] = useState<string>("5s")
@@ -152,10 +151,8 @@ const Text = (props: TextProps): JSX.Element => {
}, [animationDuration, hasOverflowScrollEffect, style, alignment, width])
useEffect(() => {
const docObj = getDocumentElement(demo)
const winObj = getWindowElement(demo)
const range = docObj?.createRange()
const sel = winObj?.getSelection()
const range = document.createRange()
const sel = window.getSelection()
const textNode = startContainer || textElementRef.current?.firstChild
if (textNode && sel && range) {

View File

@@ -16,6 +16,7 @@ const TextInput = (props: TextInputProps): JSX.Element => {
const {
action,
actionIcon,
actionIconElement,
assistiveContent,
classes,
containerClasses,
@@ -54,10 +55,12 @@ const TextInput = (props: TextInputProps): JSX.Element => {
}, [value])
const assistiveContentRender = assistiveContent ? (
"content" in assistiveContent && "onClick" in assistiveContent ? (
typeof assistiveContent === "object" &&
"content" in assistiveContent &&
"onClick" in assistiveContent ? (
<Button
classes="mb-2 p-0 f3"
variant={ArButtonVariants.LINK}
variant={ArButtonVariants.LINKNATIVE}
content={assistiveContent.content}
onClick={assistiveContent.onClick}
/>
@@ -68,7 +71,15 @@ const TextInput = (props: TextInputProps): JSX.Element => {
const labelRender = (
<div className="ar-TextInput__label-container flex-v-center">
<div className="ar-TextInput__label-container__label-assistive-text justify-content-between">
<div
className={`ar-TextInput__label-container__label-assistive-text${
assistiveContent &&
typeof assistiveContent === "object" &&
"onClick" in assistiveContent
? " d-flex flex-1 justify-content-between"
: ""
}`}
>
<label
className={`ar-TextInput__label h-100 fw-bold flex-v-center${
labelClasses ? " " + labelClasses : ""
@@ -148,6 +159,7 @@ const TextInput = (props: TextInputProps): JSX.Element => {
onChange={onLocalChange}
onFocus={focusHandler}
onBlur={blurHandler}
onKeyDown={e => e.key === "Enter" && action && action(localValue)}
placeholder={focussed ? "" : placeholder}
required={required}
value={type !== "file" ? localValue : ""}
@@ -162,7 +174,7 @@ const TextInput = (props: TextInputProps): JSX.Element => {
classes: `ar-TextInput__clear-button position-absolute ${
size === ArSizes.SMALL ? "top-point25" : "top-point5"
} ${
action && localValue ? "end-2point5" : "end-point5"
action && localValue ? "end-3point5" : "end-point5"
} cursor-pointer${localValue ? " has-value" : ""}`,
}}
events={{
@@ -173,13 +185,14 @@ const TextInput = (props: TextInputProps): JSX.Element => {
/>
{action &&
localValue &&
(actionIcon || (
(actionIconElement || (
<Icon
icon="fa.FaCheckCircle"
icon={actionIcon || "fa.FaCheckCircle"}
attributes={{
colors: { fillColor: "#28a745" },
classes: "cursor-pointer px-2 h-100",
size: "2rem",
width: "3rem",
height: "2rem",
}}
events={{ onClick: () => action(localValue) }}
/>

View File

@@ -1,6 +1,14 @@
import { useEffect, useState } from "react"
import { ToggleProps } from "@armco/types"
import {
ArPopoverSlots,
ArPopoverTriggers,
ArThemes,
ToggleProps,
} from "@armco/types"
import { useTheme } from "@armco/utils/hooks"
import Icon from "@armco/icon"
import "./Toggle.component.scss"
import PopoverV2 from "./PopoverV2"
const Toggle = (props: ToggleProps): JSX.Element => {
const {
@@ -9,6 +17,7 @@ const Toggle = (props: ToggleProps): JSX.Element => {
hideStatus,
id,
label,
assistiveContent,
required,
stretch,
toggleOnName,
@@ -25,6 +34,7 @@ const Toggle = (props: ToggleProps): JSX.Element => {
const [toggleNameLocal, setToggleNameLocal] = useState<string>(
checked ? toggleOnNameLocal : toggleOffNameLocal,
)
const { theme } = useTheme()
useEffect(() => {
isOn !== undefined && onLocalChange(isOn)
@@ -38,6 +48,27 @@ const Toggle = (props: ToggleProps): JSX.Element => {
onChange && onChange(isLocalOn)
}
const popAssContent = assistiveContent && (
<PopoverV2 trigger={ArPopoverTriggers.HOVER}>
<Icon
icon="io5.IoInformationCircleOutline"
slot={ArPopoverSlots.ANCHOR}
attributes={{
colors: {
fillColor: theme === ArThemes.DARK1 ? "#868686" : "#797979",
},
classes: "me-2",
size: "0.8rem",
}}
/>
<span slot={ArPopoverSlots.POPOVER}>
{typeof assistiveContent === "object" && "content" in assistiveContent
? assistiveContent.content
: assistiveContent}
</span>
</PopoverV2>
)
return (
<div
className={`ar-Toggle d-inline-block${stretch ? " w-100" : ""}${
@@ -65,9 +96,13 @@ const Toggle = (props: ToggleProps): JSX.Element => {
{label}
</span>
)}
{hideStatus && popAssContent}
<div className="ar-Toggle__appearance flex-center">
{!hideStatus && (
<span className="ar-Toggle__text me-2">{toggleNameLocal}</span>
<>
<span className="ar-Toggle__text me-2">{toggleNameLocal}</span>
{popAssContent}
</>
)}
<div className="ar-Toggle__switch d-inline-block" />
</div>

View File

@@ -4,7 +4,7 @@ import PopoverV2 from "./PopoverV2"
import "./Tooltip.component.scss"
const Tooltip = (props: TooltipProps): ReactNode => {
const { children, demo, ...rest } = props
const { children, ...rest } = props
const [isOpen, setOpen] = useState<boolean>()
return (
@@ -21,7 +21,6 @@ const Tooltip = (props: TooltipProps): ReactNode => {
ArAnimations.FADEINOUT,
] as Array<ArAnimations>
}
demo={demo}
isOpen={isOpen}
hideMarker
preserveMarkerSpace

View File

@@ -25,16 +25,16 @@
}
}
}
.ar-LoadableIcon {
.ar-Icon {
transition: transform 0.3s;
}
&.expanded {
max-height: 200rem;
> .ar-Popover__anchor > .ar-TreeListItem__label > .ar-LoadableIcon, > .ar-TreeListItem__label > .ar-LoadableIcon {
> .ar-Popover__anchor > .ar-TreeListItem__label > .ar-Icon, > .ar-TreeListItem__label > .ar-Icon {
transform: rotateZ(90deg);
}
}
.ar-LoadableIcon.hover-highlight {
.ar-Icon.hover-highlight {
background-color: #ddd;
}
}

3
src/TreeViz.component.scss Executable file
View File

@@ -0,0 +1,3 @@
.ar-TreeViz {
}

150
src/TreeViz.tsx Executable file
View File

@@ -0,0 +1,150 @@
import { useEffect, useRef } from "react";
import * as d3 from "d3";
import "./TreeViz.component.scss"
const dummyData = {
name: "Root",
children: [
{
name: "Child 1",
children: [
{ name: "Grandchild 1" },
{ name: "Grandchild 2" },
],
},
{
name: "Child 2",
children: [
{ name: "Grandchild 3" },
{ name: "Grandchild 4" },
],
},
],
};
/**
*
* ## TreeViz Component
*
* The `TreeViz` component is designed to visualize hierarchical relationships in a tree structure.
* It provides rich interactivity and customization options, making it ideal for use cases like task trees,
* organizational charts, or any hierarchical data visualization.
*
* ### Features:
*
* - **Tree Rendering**:
* - Displays a hierarchical tree structure using D3.js.
* - Supports multiple orientations: bottom-to-top, top-to-bottom, left-to-right, and right-to-left.
*
* - **Hover Interactivity**:
* - Displays a tooltip on hover, which can accept text, JSX, or a custom component.
* - Highlights the hovered node along with its parent and child nodes up to configurable levels.
*
* - **Customizable Nodes**:
* - Accepts custom node content, including text, JSX, components, or image URLs.
*
* - **Legend and Controls**:
* - Includes a legend and a bottom control bar with toggle buttons for enabling/disabling specific functionalities.
*
* - **Click Events**:
* - Supports callback functions for node click events, enabling custom actions.
*
* - **Export Options**:
* - Allows exporting the tree as a PDF, image, or raw JSON data.
*
* - **Dynamic Restructuring**:
* - Provides a shuffle functionality to reorganize the tree based on a selected property from the JSON data.
*
* - **Animations**:
* - Smooth animations for the initial tree rendering and during tree restructuring (e.g., shuffling).
*
* - **Drag-and-Drop**:
* - Enables drag-and-drop functionality to change parent-child associations dynamically.
*
* ### Props:
*
* - `hoverLevels`: Number of parent and child levels to highlight on hover.
* - `orientation`: Tree orientation (`"bottom-up"`, `"top-down"`, `"left-to-right"`, `"right-to-left"`).
* - `customNode`: Custom node content (text, JSX, component, or image URL).
* - `onNodeClick`: Callback function triggered when a node is clicked.
*
* ### Future Enhancements:
*
* - Additional customization options for animations and interactivity.
* - Support for larger datasets with optimized rendering.
*
* @author Mohit Nagar [mohiit1502&#64;gmail.com]
*
*/
const TreeViz = (): JSX.Element => {
const svgRef = useRef<SVGSVGElement | null>(null);
useEffect(() => {
// Clear any existing SVG content
d3.select(svgRef.current).selectAll("*").remove();
// Set dimensions
const width = 800;
const height = 600;
// Create an SVG container
const svg = d3
.select(svgRef.current)
.attr("width", width)
.attr("height", height)
.style("background-color", "#f9f9f9");
// Create a hierarchical structure from the data
const root = d3.hierarchy(dummyData);
// Create a tree layout
const treeLayout = d3.tree().size([width, height - 100]);
// Apply the tree layout to the data
treeLayout(root);
// Create links (edges)
const links = svg
.selectAll(".link")
.data(root.links())
.enter()
.append("line")
.attr("class", "link")
.attr("x1", (d) => d.source.x)
.attr("y1", (d) => d.source.y)
.attr("x2", (d) => d.target.x)
.attr("y2", (d) => d.target.y)
.attr("stroke", "#ccc")
.attr("stroke-width", 2);
// Create nodes
const nodes = svg
.selectAll(".node")
.data(root.descendants())
.enter()
.append("g")
.attr("class", "node")
.attr("transform", (d) => `translate(${d.x}, ${d.y})`);
// Add circles for nodes
nodes
.append("circle")
.attr("r", 20)
.attr("fill", "#3498db")
.attr("stroke", "#2980b9")
.attr("stroke-width", 2);
// Add text labels for nodes
nodes
.append("text")
.attr("dy", 5)
.attr("x", 0)
.attr("text-anchor", "middle")
.text((d) => d.data.name)
.style("fill", "#333")
.style("font-size", "12px");
}, []);
return <svg ref={svgRef} className="ar-TreeViz"></svg>;
};
export default TreeViz;

View File

@@ -157,7 +157,7 @@ const TypeAhead = (props: TypeAheadProps): JSX.Element => {
"content" in assistiveContent &&
"onClick" in assistiveContent ? (
<Button
containerClasses="mb-2 p-0 f3"
classes="mb-2 p-0 f3"
variant={ArButtonVariants.LINK}
content={assistiveContent.content}
onClick={assistiveContent.onClick}

View File

@@ -16,6 +16,7 @@ import {
import { post } from "@armco/utils/network"
import { isMobile as checkMobile } from "@armco/utils/helper"
import {
useClearSession,
useLoggedIn,
useNotification,
usePanelContent,
@@ -40,9 +41,10 @@ const UserOptions = (props: UserOptionsProps): JSX.Element => {
signUpUrl,
theme,
} = props
const { isLoggedIn, setLoggedIn } = useLoggedIn()
const { isLoggedIn } = useLoggedIn()
const { user } = useUser()
const { notify } = useNotification()
const clearSession = useClearSession()
const { setPanelContent: setRightPanelContent } = usePanelContent(false)
const logoutUrl =
@@ -58,10 +60,11 @@ const UserOptions = (props: UserOptionsProps): JSX.Element => {
size={ArSizes.SMALL}
variant={ArButtonVariants.LINKHOVEREFFECT}
content="Login"
theme={theme}
onClick={() =>
setRightPanelContent({
name: loginProvider || "LoginProvider",
props: {
componentName: loginProvider || "LoginProvider",
componentProps: {
// Discarded if loginProvider is available
url:
loginUrl || WEB_CONFIG.IAM[process.env.NODE_ENV] + "/login",
@@ -73,10 +76,11 @@ const UserOptions = (props: UserOptionsProps): JSX.Element => {
size={ArSizes.SMALL}
variant={ArButtonVariants.INFO}
content="Sign Up"
theme={theme}
onClick={() =>
setRightPanelContent({
name: loginProvider || "LoginProvider",
props: {
componentName: loginProvider || "LoginProvider",
componentProps: {
// Discarded if loginProvider is available
url:
signUpUrl ||
@@ -117,10 +121,11 @@ const UserOptions = (props: UserOptionsProps): JSX.Element => {
classes="w-100"
variant={ArButtonVariants.SUCCESS}
content="Login"
theme={theme}
onClick={() =>
setRightPanelContent({
name: loginProvider || "LoginProvider",
props: {
componentName: loginProvider || "LoginProvider",
componentProps: {
// Discarded if loginProvider is available
url:
loginUrl || IAMCLIENT[process.env.NODE_ENV] + "/login",
@@ -135,6 +140,7 @@ const UserOptions = (props: UserOptionsProps): JSX.Element => {
classes="ar-UserOptions__btn-standout mt-2 w-100"
variant={ArButtonVariants.LINK}
content="Logout"
theme={theme}
onClick={() => {
post(logoutUrl, user || {}).then((res) => {
if (res.status === 200) {
@@ -143,8 +149,8 @@ const UserOptions = (props: UserOptionsProps): JSX.Element => {
message: "You've been logged out!",
uid: uuid(),
})
setLoggedIn(false)
}
clearSession()
onLogout && onLogout()
})
}}

432
src/enums.ts Normal file
View File

@@ -0,0 +1,432 @@
export enum ArTabType {
CLASSIC = "classic",
MODERN = "modern",
MINIMAL = "minimal",
}
export enum ArAriaRoles {
TAB = "tab",
}
export enum ArAlertType {
SUCCESS = "success",
WARNING = "warning",
ERROR = "error",
INFORMATION = "information",
}
export enum ArSizes {
XSMALL = "xsmall",
SMALL = "small",
REGULAR = "regular",
LARGE = "large",
XLARGE = "xlarge",
}
export enum ArLoaderTypes {
BAR = "bar",
SHAPES = "shapes",
CIRCLE = "circle",
CUSTOM = "custom",
}
export enum ArButtonVariants {
SUCCESS = "success",
DANGER = "danger",
PRIMARY = "primary",
SECONDARY = "secondary",
TERTIARY = "tertiary",
WARNING = "warning",
INFO = "info",
DARK = "dark",
LIGHT = "light",
LINK = "link",
LINKNATIVE = "link-native",
LINKHOVEREFFECT = "link-hover",
}
export enum ArButtonTypes {
SUBMIT = "submit",
BUTTON = "button",
RESET = "reset",
}
export enum ArPlacement {
RIGHT = "right",
LEFT = "left",
TOP = "top",
BOTTOM = "bottom",
}
export enum ArPopoverSlots {
POPOVER = "popover",
ANCHOR = "anchor",
}
export enum ArAnimations {
FADEINOUT = "fade",
EXPANDSHRINK = "expand-shrink",
}
export enum ArPopoverPositions {
TOPLEFT = "top-left",
TOPRIGHT = "top-right",
TOPCENTER = "top-center",
RIGHTTOP = "right-top",
RIGHTBOTTOM = "right-bottom",
RIGHTCENTER = "right-center",
BOTTOMLEFT = "bottom-left",
BOTTOMRIGHT = "bottom-right",
BOTTOMCENTER = "bottom-center",
LEFTTOP = "left-top",
LEFTBOTTOM = "left-bottom",
LEFTCENTER = "left-center",
BOTTOM = "bottom",
RIGHT = "right",
LEFT = "left",
TOP = "top",
AUTO = "auto",
}
export enum ArPopoverTriggers {
HOVER = "hover",
CLICK = "click",
}
export enum ArListStyles {
ORDERED = "ordered",
UNORDERED = "unordered",
UNSTYLED = "unstyled",
}
export enum ArListVariants {
FLAT = "flat",
LINK = "link",
}
// TODO: Tag for related component (probably d3 based) move to separate component
export enum ArVisualizationTypes {
BUBBLE = "bubble",
}
export enum ArIconTileTypes {
COMFY = "comfy",
COMPACT = "compact",
LIST = "list",
}
export enum ArTableLayouts {
COMFORTABLE = "comfortable",
COMPACT = "compact",
NORMAL = "normal",
}
export enum ArBadgeType {
INPROGRESS = "inprogress",
COMPLETE = "complete",
DEFERRED = "deferred",
ATRISK = "atrisk",
}
export enum ArJobStatus {
RUNNING = "running",
STOPPED = "stopped",
SUSPENDED = "suspended",
ARCHIVED = "archived",
}
export enum ArPageTriggers {
SELECTOR = "selector",
SCROLL = "scroll",
}
export enum ArPillSizes {
LARGE = "large",
MEDIUM = "medium",
SMALL = "small",
}
export enum RecusionConditionTypes {
KEY_EXISTS = "keyExists",
KEY_VALUE = "keyValue",
}
export enum ArAccordionVariants {
LIMITED = "limited",
FREE = "free",
}
export enum ArAccordionStyles {
STACKED = "stacked",
COMFORTABLE = "comfortable",
}
export enum ArAnimationInjectionTypes {
ADD = "add",
REPLACE = "replace",
}
export enum ArAnimationProperty {
POSITION = "p",
OPACITY = "o",
ANCHOR = "a",
ROTATE = "r",
SCALE = "s",
}
export enum ArThemes {
LIGHT1 = "th-light-1",
DARK1 = "th-dark-1",
}
export enum ArDateFormats {
DDMMYYYY = "DDMMYYYY",
DDMMYY = "DDMMYY",
MMDDYYYY = "MMDDYYYY",
MMDDYY = "MMDDYY",
YYMMDD = "YYMMDD",
YYYYMMDD = "YYYYMMDD",
DDMMMYY = "DDMMMYY",
DDMMMYYYY = "DDMMMYYYY",
MMMDDYY = "MMMDDYY",
MMMDDYYYY = "MMMDDYYYY",
YYYYMMMDD = "YYYYMMMDD",
YYMMMDD = "YYMMMDD",
}
export enum ArDateMasks {
DEFAULT = "ddd mmm dd yyyy HH:MM:ss",
SHORTDATE = "m/d/yy",
PADDEDSHORTDATE = "mm/dd/yyyy",
MEDIUMDATE = "mmm d, yyyy",
LONGDATE = "mmmm d, yyyy",
FULLDATE = "dddd, mmmm d, yyyy",
SHORTTIME = "h:MM TT",
MEDIUMTIME = "h:MM:ss TT",
LONGTIME = "h:MM:ss TT Z",
ISODATE = "yyyy-mm-dd",
ISOTIME = "HH:MM:ss",
ISODATETIME = "yyyy-mm-dd'T'HH:MM:sso",
ISOUTCDATETIME = "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'",
EXPIRESHEADERFORMAT = "ddd, dd mmm yyyy HH:MM:ss Z",
}
export enum ArCalViews {
CALENDAR = "calendar",
MONTH_YEAR_SELECTOR = "month-year-selector",
EVENT_FORM = "event-form",
}
export enum ArMonthSelectorViews {
DECADE = "decade",
YEAR = "year",
MONTH = "month",
}
export enum ArEventStates {
DRAFT = "draft",
SCHEDULED = "scheduled",
EXPIRED = "expired",
CANCELLED = "cancelled",
DEFERRED = "deferred",
}
export enum ArEventTypes {
TASK = "task",
EVENT = "event",
BIRTHDAY = "birthday",
MEETING = "meeting",
}
export enum ArSchedules {
TODAY = "today",
TOMORROW = "tomorrow",
NEXTWEEK = "next-week",
NEXTMONTH = "next-month",
CUSTOM = "custom",
}
export enum ArLabelValueVariants {
FLAT = "flat",
STACKED = "stacked",
FLATBOXED = "flat-boxed",
STACKBOXED = "stack-boxed",
}
export enum ArDropdownVariants {
SELECTIONSASLINKS = "selections-as-links",
SELECTIONSASPILLS = "selections-as-pills",
}
export enum ArWizardNavigationTypes {
STANDARD = "standard",
OVERLAY = "overlay",
OVERLAYPROMINENT = "overlay-prominent",
EXTERNAL = "external",
}
export enum ArWebPageLayout {
TWOCOL = "Two Column",
THREECOL = "Three Column",
GRID = "Grid",
CARD = "Card",
HEROLINEARCONTENTBLOCKS = "Hero with linear content blocks",
HEROSTAGGEREDARCONTENTBLOCKS = "Hero with staggered content blocks",
HEROSTAGGEREDREVERSEDARCONTENTBLOCKS = "Hero with staggered content blocks reverse layout",
STACKED = "Stacked",
TABBED = "Tabbed",
FULL = "Full screen background with content overlay",
SPLIT = "Split screen",
CAROUSEL = "Carousel",
CUSTOM = "Custom",
}
export enum ArLayoutSlots {
HEADER = "header",
FOOTER = "footer",
DRAWER = "drawer",
SIDEPANEL = "sidepanel",
}
export enum ArHeaderSlots {
LOGO = "logo",
SEARCH = "search",
NAVBAR = "navbar",
USER = "user",
NOTIFICATIONS = "notifications",
ACTIONS = "actions",
SETTINGS = "settings",
}
export enum ArComponentLevels {
PAGE = "page",
MAIN = "main",
}
export enum ArPortalManagementType {
SELF = "self",
CONTEXT = "context",
}
export enum ArDefaultLoginPage {
LOGIN = "login",
SINGUP = "signup",
}
export enum ArLoginProviders {
ARMCO = "ArmcoIamProvider",
IAM = "StuffleIamProvider",
}
export enum ArDndItemTypes {
TREELISTITEM = "tree-list-item",
COMPONENTSLOT = "component-slot",
GENERIC = "generic",
ICON = "icon",
}
export enum ArSlotViewMode {
PREVIEW = "preview",
BUILD = "build",
RELEASE = "release",
ROWCONTROLLER = "row-controller",
COLCONTROLLER = "col-controller",
}
export enum ArDisplayTypes {
BLOCK = "block",
INLINE = "inline",
INLINEBLOCK = "inline-block",
GRID = "grid",
FLEX = "flex",
INLINEFLEX = "inline-flex",
}
export enum ArDirections {
NORTH = "n",
NORTHEAST = "ne",
EAST = "e",
SOUTHEAST = "se",
SOUTH = "s",
SOUTHWEST = "sw",
WEST = "w",
NORTHWEST = "nw",
}
export enum ArComponentResources {
STUFFLE = "stuffle",
MATERIAL = "material",
BOOTSTRAP = "bootstrap",
BIT = "bit",
}
export enum ArTextSizes {
H1 = "h1",
H2 = "h2",
H3 = "h3",
H4 = "h4",
H5 = "h5",
H6 = "h6",
}
export enum ArContentTypes {
COMPONENT = "component",
ICON = "icon",
IMAGE = "image",
PDF = "pdf",
TXT = "txt",
STRING = "string",
}
export enum ArProgress {
IN_PROGRESS = "IN_PROGRESS",
COMPLETED = "COMPLETED",
FAILED = "FAILED",
}
export enum ArFormatTags {
bold = "b",
italic = "i",
underline = "u",
strikethrough = "s",
code = "code",
subscript = "sub",
superscript = "sup",
list = "li",
}
export enum ArIconSourceTypes {
URL = "URL",
identifier = "identifier",
svgString = "svgString",
b64 = "b64",
raw = "raw",
}
export enum ArValidImageMimeTypes {
JPEG = "image/jpeg",
PNG = "image/png",
GIF = "image/gif",
WEBP = "image/webp",
SVG = "image/svg+xml",
TIFF = "image/tiff",
BMP = "image/bmp",
ICON = "image/x-icon",
}
export enum ArEditorEvents {
CLICK = "click",
INPUT = "input",
SELECTIONCHANGE = "selectionchange",
KEYDOWN = "keydown",
ENTER = "enter",
BACKSPACE = "backspace",
DELETE = "delete",
FORMAT = "format",
BOLD = "bold",
ITALIC = "italic",
UNDERLINE = "underline",
STRIKETHROUGH = "strikethrough",
SUBSCRIPT = "subscript",
SUPERSCRIPT = "superscript",
}

View File

@@ -1,6 +1,7 @@
import "./styles/_global.scss"
/* PLOP_INJECT_IMPORT */
export { default as TreeViz } from "./TreeViz"
export { default as Anchor } from "./Anchor"
export { default as Card } from "./Card"
export { default as Component_404 } from "./Component_404"
@@ -27,8 +28,10 @@ export { default as LabelValue } from "./LabelValue"
export { default as LearnLink } from "./LearnLink"
export { default as Link } from "./Link"
export { default as List } from "./List"
export { default as ListItem } from "./ListItem"
export { default as Loader } from "./Loader"
export { default as Mask } from "./Mask"
export { default as MenuButton } from "./MenuButton"
export { default as Modal } from "./Modal"
export { default as Notification } from "./Notification"
export { default as NumericStepper } from "./NumericStepper"

View File

@@ -39,6 +39,10 @@ code {
.label {
margin-bottom: 0.5rem;
font-weight: bold;
&.light {
color: var(--ar-color-label);
}
}
.form-component {
@@ -312,6 +316,10 @@ label.required:after {
right: 2.5rem;
}
.end-3point5 {
right: 3.5rem;
}
.z-1 {
z-index: 1 !important;
}
@@ -499,6 +507,26 @@ label.required:after {
will-change: transform;
}
.custom-scrollbar {
&::-webkit-scrollbar {
width: 4px;
}
/* Track */
&::-webkit-scrollbar-track {
background: #f1f1f1;
}
/* Handle */
&::-webkit-scrollbar-thumb {
background: #bbb;
border-radius: 2px;
&:hover {
background: #888;
}
}
}
.rotate {
animation: rotating 0.5s linear infinite;
}

View File

@@ -51,6 +51,7 @@
--ar-color-primary: #0000f3;
--ar-color-primary-faded: rgba(0, 0, 242, 0.7);
--ar-color-secondary: #525252;
--ar-color-label: var(--ar-color-obscure-3);
--ar-default-widget-color: #676767;
--ar-bg-base: #FCFCF8;
--ar-bg-base-light: #FEFEFA;
@@ -112,6 +113,7 @@
--ar-color-primary: #3232d8;
--ar-color-primary-faded: rgba(50, 50, 216, 0.7);
--ar-color-secondary: #adadad;
--ar-color-label: var(--ar-color-obscure-3);
--ar-bg-base: #101010;
--ar-bg-base-light: #010101;
--ar-bg: black;

88
vite-dev.config.ts Normal file
View File

@@ -0,0 +1,88 @@
import { defineConfig } from "vitest/config"
import { resolve } from "path"
import { glob } from "glob"
import react from "@vitejs/plugin-react"
import svgr from "vite-plugin-svgr"
import dts from "vite-plugin-dts"
import { libInjectCss } from "vite-plugin-lib-inject-css"
function ClosePlugin() {
return {
name: "ClosePlugin", // required, will show up in warnings and errors
// use this to catch errors when building
buildEnd(error) {
if (error) {
console.error("Error bundling")
console.error(error)
process.exit(1)
} else {
console.log("Build ended")
}
},
// use this to catch the end of a build without errors
closeBundle() {
console.log("Bundle closed")
process.exit(0)
},
}
}
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react(),
svgr(),
libInjectCss(),
dts({ outDir: "build/types" }),
ClosePlugin(),
],
css: {
preprocessorOptions: {
scss: {
api: "modern-compiler",
},
},
},
build: {
outDir: "build",
sourcemap: true,
lib: {
entry: glob.sync(resolve(__dirname, "src/**/!(*.d).{ts,tsx}")),
},
rollupOptions: {
treeshake: true,
external: [
new RegExp("^react.*"),
new RegExp("^highcharts.*"),
"d3",
new RegExp("^@armco/.*"),
"@armco/icon",
],
output: [
{
format: "es",
dir: "build/es",
entryFileNames: "[name].js",
chunkFileNames: "[name]-chunk.js",
assetFileNames: "assets/[name][extname]",
},
{
format: "cjs",
dir: "build/cjs",
entryFileNames: "[name].js",
chunkFileNames: "[name]-chunk.js",
assetFileNames: "assets/[name][extname]",
},
],
},
},
assetsInclude: ["**/*.png", "**/*.jpg", "**/*.jpeg", "**/*.gif", "**/*.svg"],
test: {
globals: true,
environment: "jsdom",
setupFiles: "src/setupTests",
mockReset: true,
},
})