From cb34bc19bc4de8bef79c5407781da903e15e281a Mon Sep 17 00:00:00 2001 From: vikas-cldcvr Date: Thu, 15 Feb 2024 15:25:58 +0530 Subject: [PATCH 01/17] FDS-648 f-icon-picker element added --- .../src/components/f-div/f-div-global.scss | 30 ++ .../flow-core/src/components/f-div/f-div.ts | 9 +- .../_f-icon-picker-variables.scss | 30 ++ .../f-icon-picker/f-icon-picker-global.scss | 18 + .../f-icon-picker/f-icon-picker.scss | 99 ++++++ .../components/f-icon-picker/f-icon-picker.ts | 333 ++++++++++++++++++ packages/flow-core/src/index.ts | 1 + stories/flow-core/f-div.stories.ts | 10 +- stories/flow-core/f-icon-picker.stories.ts | 327 +++++++++++++++++ 9 files changed, 855 insertions(+), 2 deletions(-) create mode 100644 packages/flow-core/src/components/f-icon-picker/_f-icon-picker-variables.scss create mode 100644 packages/flow-core/src/components/f-icon-picker/f-icon-picker-global.scss create mode 100644 packages/flow-core/src/components/f-icon-picker/f-icon-picker.scss create mode 100644 packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts create mode 100644 stories/flow-core/f-icon-picker.stories.ts diff --git a/packages/flow-core/src/components/f-div/f-div-global.scss b/packages/flow-core/src/components/f-div/f-div-global.scss index 3e7d5b7af..4666a5196 100644 --- a/packages/flow-core/src/components/f-div/f-div-global.scss +++ b/packages/flow-core/src/components/f-div/f-div-global.scss @@ -204,6 +204,36 @@ f-div { max-height: 48px; } } + + // if selected state is notch-top, creating pseudo element to create notch + &[selected="notch-top"] { + &::after { + position: absolute; + top: 0; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + left: 4px; + right: 4px; + max-width: 48px; + border-top: 4px solid var(--color-success-default); + content: ""; + } + } + // if selected state is notch-bottom, creating pseudo element to create notch + &[selected="notch-bottom"] { + position: relative; + &::after { + position: absolute; + bottom: 0px; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + right: 4px; + left: 4px; + max-width: 48px; + border-bottom: 4px solid var(--color-success-default); + content: ""; + } + } } } diff --git a/packages/flow-core/src/components/f-div/f-div.ts b/packages/flow-core/src/components/f-div/f-div.ts index e14921433..7156cea75 100644 --- a/packages/flow-core/src/components/f-div/f-div.ts +++ b/packages/flow-core/src/components/f-div/f-div.ts @@ -235,7 +235,14 @@ export class FDiv extends FRoot { * @attribute Sets the f-div to a selected state. Select between border, background, or notch based on your use case. */ @property({ reflect: true, type: String }) - selected?: "none" | "background" | "border" | "notch-right" | "notch-left" = "none"; + selected?: + | "none" + | "background" + | "border" + | "notch-right" + | "notch-left" + | "notch-top" + | "notch-bottom" = "none"; /** * @attribute Sticky property defines a f-div’s position based on the scroll position of the container diff --git a/packages/flow-core/src/components/f-icon-picker/_f-icon-picker-variables.scss b/packages/flow-core/src/components/f-icon-picker/_f-icon-picker-variables.scss new file mode 100644 index 000000000..c32551e26 --- /dev/null +++ b/packages/flow-core/src/components/f-icon-picker/_f-icon-picker-variables.scss @@ -0,0 +1,30 @@ +$sizes: ( + "medium": 36px, + "small": 28px +); + +$state-colors: ( + "primary": var(--color-primary-default), + "success": var(--color-success-default), + "warning": var(--color-warning-default), + "danger": var(--color-danger-default) +); + +$variants: ( + "curved": 4px, + "round": 22px, + "block": 0px +); + +$categories: ( + "fill": ( + "background": var(--color-input-default), + "hover": var(--color-input-default-hover), + "border": 1px solid var(--color-input-default) + ), + "outline": ( + "background": transparent, + "hover": var(--color-surface-default-hover), + "border": 1px solid var(--color-border-default) + ) +); diff --git a/packages/flow-core/src/components/f-icon-picker/f-icon-picker-global.scss b/packages/flow-core/src/components/f-icon-picker/f-icon-picker-global.scss new file mode 100644 index 000000000..e4e01e446 --- /dev/null +++ b/packages/flow-core/src/components/f-icon-picker/f-icon-picker-global.scss @@ -0,0 +1,18 @@ +@import "./../../mixins/scss/mixins"; +@import "./f-icon-picker-variables"; + +f-emoji-picker { + display: flex; + flex: 1 0 auto; + &[disabled] { + @include disabled(); + } + &[state="default"] { + @include input-color("default"); + } + @each $state, $color in $state-colors { + &[state="#{$state}"] { + @include input-color($state); + } + } +} diff --git a/packages/flow-core/src/components/f-icon-picker/f-icon-picker.scss b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.scss new file mode 100644 index 000000000..dbc26ae34 --- /dev/null +++ b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.scss @@ -0,0 +1,99 @@ +@use "sass:map"; + +// common mixins imported from this file +@import "./../../mixins/scss/mixins"; +@import "./f-icon-picker-variables"; +/** +START : scss maps to hold repsective attribute values +**/ + +:host { + .f-icon-picker { + @include base(); + cursor: pointer; + align-items: center; + display: flex; + justify-content: space-between; + gap: 8px; + max-width: 58px; + > f-div:not([placeholder]) { + font-style: normal; + font-weight: 325; + line-height: 18px; + color: var(--color-text-subtle); + width: fit-content !important; + &[size="small"] { + font-size: 15px; + } + &[size="medium"] { + font-size: 21px; + } + } + padding: 0px 8px; + + @each $variant, $value in $variants { + &[variant="#{$variant}"] { + border-radius: $value; + } + } + @each $size, $value in $sizes { + &[size="#{$size}"] { + height: $value; + } + } + @each $state, $color in $state-colors { + &[state="#{$state}"] { + @each $category, $value in $categories { + &[category="#{$category}"] { + background-color: map.get($value, "background"); + border: 1px solid $color; + &:hover { + background-color: map.get($value, "hover"); + } + } + &[category="transparent"][variant="block"] { + background-color: transparent; + border-top: 0px; + border-bottom: 1px solid $color; + border-left: 0px; + border-right: 0px; + &:hover { + background-color: var(--color-surface-default-hover); + } + } + } + } + } + + &[state="default"] { + @each $category, $value in $categories { + &[category="#{$category}"] { + background-color: map.get($value, "background"); + border: map.get($value, "border"); + &:hover { + background-color: map.get($value, "hover"); + } + } + &[category="transparent"][variant="block"] { + background-color: transparent; + border-top: 0px; + border-bottom: 1px solid var(--color-border-default); + border-left: 0px; + border-right: 0px; + &:hover { + background-color: var(--color-surface-default-hover); + } + } + } + &:focus { + outline: none; + border: 1px solid var(--color-primary-default); + } + } + } + div.f-icon-picker[disabled] { + @include disabled(); + pointer-events: none; + opacity: 1; + } +} diff --git a/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts new file mode 100644 index 000000000..47ca8e70c --- /dev/null +++ b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts @@ -0,0 +1,333 @@ +import { html, unsafeCSS } from "lit"; +import { customElement, property, query, queryAssignedElements } from "lit/decorators.js"; +import { FRoot } from "./../../mixins/components/f-root/f-root"; +import globalStyle from "./f-icon-picker-global.scss?inline"; +import { injectCss } from "@ollion/flow-core-config"; +import { FDiv } from "../f-div/f-div"; +import { FPopover } from "../f-popover/f-popover"; +import eleStyle from "./f-icon-picker.scss?inline"; +import { FText } from "../f-text/f-text"; +import { FIcon } from "../f-icon/f-icon"; +import { FIconButton } from "../f-icon-button/f-icon-button"; +injectCss("f-icon-picker", globalStyle); + +export type FIconPickerState = "primary" | "default" | "success" | "warning" | "danger"; + +import SystemIconPack from "@ollion/flow-system-icon/dist/types/icon-pack"; +import ProductIconPack from "@ollion/flow-product-icon/dist/types/icon-pack"; +import GcpIconPack from "@ollion/flow-gcp-icon/dist/types/icon-pack"; +import AwsIconPack from "@ollion/flow-aws-icon/dist/types/icon-pack"; +import { FSearch } from "../f-search/f-search"; + +const defaultIconPacks = { + System: SystemIconPack, + Product: ProductIconPack, + GCP: GcpIconPack, + AWS: AwsIconPack +}; + +@customElement("f-icon-picker") +export class FIconPicker extends FRoot { + /** + * css loaded from scss file + */ + static styles = [ + unsafeCSS(globalStyle), + unsafeCSS(eleStyle), + ...FDiv.styles, + ...FText.styles, + ...FPopover.styles, + ...FIcon.styles, + ...FIconButton.styles, + ...FSearch.styles + ]; + + /** + * @attribute Defines the value of f-icon-picker + */ + @property({ reflect: true, type: String }) + value?: string; + + /** + * @attribute show/remove clear icon + */ + @property({ reflect: true, type: Boolean }) + clear?: boolean = true; + + /** + * @attribute Defines the size of f-icon-picker. size can be two types - `medium` | `small` + */ + @property({ reflect: true, type: String }) + size?: "medium" | "small" = "medium"; + + /** + * @attribute Defines the placeholder of f-icon-picker + */ + @property({ reflect: true, type: String }) + placeholder?: string; + + /** + * @attribute Variants are various visual representations of icon picker. + */ + @property({ reflect: true, type: String }) + variant?: "curved" | "round" | "block" = "curved"; + + /** + * @attribute Categories are various visual representations of icon picker. + */ + @property({ reflect: true, type: String }) + category?: "fill" | "outline" | "transparent" = "fill"; + + /** + * @attribute States are used to communicate purpose and connotations. + */ + @property({ reflect: true, type: String }) + state?: FIconPickerState = "default"; + + /** + * @attribute Sets the f-icon-picker to disabled state. + */ + @property({ reflect: true, type: Boolean }) + disabled?: boolean = false; + + /** + * @attribute assigned elements inside slot label + */ + @queryAssignedElements({ slot: "label" }) + _labelNodes!: NodeListOf; + + /** + * @attribute assigned elements inside slot description + */ + @queryAssignedElements({ slot: "description" }) + _descriptionNodes!: NodeListOf; + + /** + * @attribute assigned elements inside slot help + */ + @queryAssignedElements({ slot: "help" }) + _helpNodes!: NodeListOf; + + @query("#f-emoji-picker-header") + emojiPickerHeader!: FDiv; + + @query("#f-emoji-picker-error") + emojiPickerError!: FDiv; + + @query("#label-slot") + labelSlot!: HTMLElement; + + @query("slot[name='description']") + descriptionSlot!: HTMLElement; + + @query("slot[name='help']") + helpSlot!: HTMLElement; + + @query(".f-icon-picker") + iconPicker!: HTMLDivElement; + + @query(".f-icon-picker-popover") + iconPickerPopover!: FPopover; + + clearValue() { + /** + * @event input + */ + const event = new CustomEvent("input", { + detail: { + name: undefined, + value: undefined + }, + bubbles: true, + composed: true + }); + this.value = undefined; + this.dispatchEvent(event); + } + handleIconSeletion(name: string, value: string) { + /** + * @event input + */ + const event = new CustomEvent("input", { + detail: { + name, + value + }, + bubbles: true, + composed: true + }); + this.value = name; + this.dispatchEvent(event); + } + render() { + /** + * clear conditional display + */ + const clearIcon = this.clear + ? html` + ${this.value + ? html` + ` + : ""} + ` + : ""; + + /** + * conditional display of inpu value or plcaeholder + */ + const inputValue = this.value + ? html`` + : html``; + + // render empty string, since there no need of any child element + return html` + + + + + + + + + + + + +
{ + e.stopPropagation(); + this.toggleIconPicker(true); + }} + > + + ${inputValue} + + ${clearIcon} +
+ +
+ + + + + + + + + + + + + + + + + + + + + ${Object.entries(defaultIconPacks).map(([name, icons]) => { + return html` + ${name} + + + ${Object.entries(icons).map(([name, svg]) => { + return html` this.handleIconSeletion(name, svg)} + padding="small" + height="hug-content" + >`; + })} + `; + })} + + + + `; + } + + /** + * open/close picker + * @param value boolean + */ + toggleIconPicker(value: boolean) { + this.iconPickerPopover.target = this.iconPicker; + this.iconPickerPopover.open = value; + } +} + +/** + * Required for typescript + */ +declare global { + export interface HTMLElementTagNameMap { + "f-icon-picker": FIconPicker; + } +} diff --git a/packages/flow-core/src/index.ts b/packages/flow-core/src/index.ts index 5f60adc03..db1672f84 100644 --- a/packages/flow-core/src/index.ts +++ b/packages/flow-core/src/index.ts @@ -49,6 +49,7 @@ export * from "./components/f-form-field/f-form-field"; export * from "./components/f-input/f-input-light"; export * from "./components/f-color-picker/f-color-picker"; export * from "./components/f-countdown/f-countdown"; +export * from "./components/f-icon-picker/f-icon-picker"; export { html } from "lit"; diff --git a/stories/flow-core/f-div.stories.ts b/stories/flow-core/f-div.stories.ts index 1fd9eaed7..6cdd55539 100644 --- a/stories/flow-core/f-div.stories.ts +++ b/stories/flow-core/f-div.stories.ts @@ -248,7 +248,15 @@ export const Playground = { selected: { control: "select", - options: ["background", "border", "notch-right", "notch-left", "None"] + options: [ + "background", + "border", + "notch-right", + "notch-left", + "notch-top", + "notch-bottom", + "none" + ] }, highlight: { diff --git a/stories/flow-core/f-icon-picker.stories.ts b/stories/flow-core/f-icon-picker.stories.ts new file mode 100644 index 000000000..c7ad01099 --- /dev/null +++ b/stories/flow-core/f-icon-picker.stories.ts @@ -0,0 +1,327 @@ +import { html } from "lit-html"; + +export default { + title: "@ollion/flow-core/f-icon-picker", + + parameters: { + controls: { + hideNoControlsWarning: true + } + } +}; + +export const Playground = { + render: (args: Record) => { + const handleInput = (e: CustomEvent) => { + console.log("input event", e); + }; + + return html` + + + + Label + Help! + + + + `; + }, + + name: "Playground", + + argTypes: { + value: { + control: "text" + }, + + placeholder: { + control: "text" + }, + + variant: { + control: "select", + options: ["curved", "round", "block"] + }, + + category: { + control: "select", + options: ["fill", "transparent", "outline"] + }, + + state: { + control: "select", + options: ["default", "success", "primary", "warning", "danger"] + }, + + size: { + control: "radio", + options: ["small", "medium"] + }, + + disabled: { + control: "boolean" + }, + + clear: { + control: "boolean" + } + }, + + args: { + value: undefined, + placeholder: undefined, + variant: "round", + category: "fill", + state: "default", + size: "medium", + disabled: false, + clear: true + } +}; + +export const Variant = { + render: () => { + const variants = ["curved", "round", "block"]; + + const value = "i-plus"; + const handleValue = (e: CustomEvent) => { + console.log("input event", e); + }; + + return html` + + ${variants.map( + item => html` + + Label + Help! + ` + )} + + `; + }, + + name: "variant" +}; + +export const Category = { + render: () => { + const categories = ["fill", "outline", "transparent"]; + const value = ""; + + const handleValue = (e: CustomEvent) => { + console.log("input event", e); + }; + + return html` + + ${categories.map( + item => html` + + Label + Help! + ` + )} + + `; + }, + + name: "category" +}; + +export const Value = { + render: () => { + const value = "⌛"; + + const handleValue = (e: CustomEvent) => { + console.log("input event", e); + }; + + return html` + + + + Label + Help! + + `; + }, + + name: "value" +}; + +export const Placeholder = { + render: () => { + const value = ""; + + const handleValue = (e: CustomEvent) => { + console.log("input event", e); + }; + + return html` + + + + Label + Help! + + `; + }, + + name: "placeholder" +}; + +export const Size = { + render: () => { + const sizes = ["small", "medium"]; + const value = ""; + + const handleValue = (e: CustomEvent) => { + console.log("input event", e); + }; + + return html` + + ${sizes.map( + item => html` + + Label + Help! + ` + )} + + `; + }, + + name: "size" +}; + +export const State = { + render: () => { + const states = [ + ["default", "primary", "success"], + ["danger", "warning", "default"] + ]; + const value = ""; + + const handleValue = (e: CustomEvent) => { + console.log("input event", e); + }; + + return html` + + ${states.map( + item => + html` + ${item.map( + state => + html` + Label + Help! + ` + )} + ` + )} + + `; + }, + + name: "state" +}; + +export const Flags = { + render: () => { + const value = ""; + + const handleValue = (e: CustomEvent) => { + console.log("input event", e); + }; + + return html` + + disabled=true + + + Label + Help! + + + + clear=false + + + Label + Help! + + + + close-on-select=true + + + Label + Help! + + + `; + }, + + name: "Flags" +}; From a4052965d05a99e268e01047f3ea1de17b9d1baf Mon Sep 17 00:00:00 2001 From: vikas-cldcvr Date: Thu, 15 Feb 2024 16:20:20 +0530 Subject: [PATCH 02/17] FDS-648 custom icon source implemented --- .../components/f-icon-button/f-icon-button.ts | 18 ++-- .../components/f-icon-picker/f-icon-picker.ts | 98 +++++++------------ .../flow-core/src/components/f-icon/f-icon.ts | 73 ++++++++------ stories/flow-core/f-icon-picker.stories.ts | 46 +++++++++ 4 files changed, 138 insertions(+), 97 deletions(-) diff --git a/packages/flow-core/src/components/f-icon-button/f-icon-button.ts b/packages/flow-core/src/components/f-icon-button/f-icon-button.ts index a3d58d7ed..a2c5858bf 100644 --- a/packages/flow-core/src/components/f-icon-button/f-icon-button.ts +++ b/packages/flow-core/src/components/f-icon-button/f-icon-button.ts @@ -6,7 +6,7 @@ import { FRoot } from "../../mixins/components/f-root/f-root"; import { classMap } from "lit-html/directives/class-map.js"; import { unsafeSVG } from "lit-html/directives/unsafe-svg.js"; import loader from "../../mixins/svg/loader"; -import { FIcon } from "../f-icon/f-icon"; +import { FIcon, FIconSource } from "../f-icon/f-icon"; import { FCounter } from "../f-counter/f-counter"; import { validateHTMLColorName } from "validate-color"; import { validateHTMLColor } from "validate-color"; @@ -21,9 +21,9 @@ const variants = ["round", "curved", "block"] as const; const categories = ["fill", "outline", "transparent", "packed"] as const; const sizes = ["large", "medium", "small", "x-small"] as const; -export type FIconButtonVariant = (typeof variants)[number]; -export type FIconButtonType = (typeof categories)[number]; -export type FIconButtonSize = (typeof sizes)[number]; +export type FIconButtonVariant = typeof variants[number]; +export type FIconButtonType = typeof categories[number]; +export type FIconButtonSize = typeof sizes[number]; export type FIconButtonState = | "primary" | "danger" @@ -55,18 +55,18 @@ export class FIconButton extends FRoot { /** * @attribute Icon property defines what icon will be displayed on the icon. It can take the icon name from a library , any inline SVG or any URL for the image. */ - @property({ type: String }) - icon!: string; + @property({ type: [String, Object], reflect: true }) + icon!: FIconSource; /** * @attribute Variants are various representations of an icon button. For example an icon button can be round, curved or block. */ - @property({ type: String }) + @property({ type: String, reflect: true }) variant?: FIconButtonVariant = "round"; /** * @attribute Type of f-icon-button */ - @property({ type: String }) + @property({ type: String, reflect: true }) category?: FIconButtonType = "fill"; /** @@ -78,7 +78,7 @@ export class FIconButton extends FRoot { /** * @attribute Size of f-icon-button */ - @property({ type: String }) + @property({ type: String, reflect: true }) state?: FIconButtonState = "primary"; /** diff --git a/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts index 47ca8e70c..4e8796bcf 100644 --- a/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts +++ b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts @@ -7,25 +7,19 @@ import { FDiv } from "../f-div/f-div"; import { FPopover } from "../f-popover/f-popover"; import eleStyle from "./f-icon-picker.scss?inline"; import { FText } from "../f-text/f-text"; -import { FIcon } from "../f-icon/f-icon"; +import { FIcon, FIconCustomSource } from "../f-icon/f-icon"; import { FIconButton } from "../f-icon-button/f-icon-button"; +import { FSearch } from "../f-search/f-search"; injectCss("f-icon-picker", globalStyle); export type FIconPickerState = "primary" | "default" | "success" | "warning" | "danger"; -import SystemIconPack from "@ollion/flow-system-icon/dist/types/icon-pack"; -import ProductIconPack from "@ollion/flow-product-icon/dist/types/icon-pack"; -import GcpIconPack from "@ollion/flow-gcp-icon/dist/types/icon-pack"; -import AwsIconPack from "@ollion/flow-aws-icon/dist/types/icon-pack"; -import { FSearch } from "../f-search/f-search"; - -const defaultIconPacks = { - System: SystemIconPack, - Product: ProductIconPack, - GCP: GcpIconPack, - AWS: AwsIconPack -}; - +export type FIconPickerCategories = + | { + name: string; + categoryIcon: string | URL; + icons: FIconCustomSource[]; + }[]; @customElement("f-icon-picker") export class FIconPicker extends FRoot { /** @@ -45,8 +39,8 @@ export class FIconPicker extends FRoot { /** * @attribute Defines the value of f-icon-picker */ - @property({ reflect: true, type: String }) - value?: string; + @property({ reflect: true, type: Object }) + value?: FIconCustomSource; /** * @attribute show/remove clear icon @@ -90,6 +84,14 @@ export class FIconPicker extends FRoot { @property({ reflect: true, type: Boolean }) disabled?: boolean = false; + /** + * @attribute Specify icon set. + */ + @property({ type: Object }) + categories!: FIconPickerCategories; + + readonly required = ["categories"]; + /** * @attribute assigned elements inside slot label */ @@ -144,19 +146,16 @@ export class FIconPicker extends FRoot { this.value = undefined; this.dispatchEvent(event); } - handleIconSeletion(name: string, value: string) { + handleIconSeletion(value: FIconCustomSource) { /** * @event input */ const event = new CustomEvent("input", { - detail: { - name, - value - }, + detail: value, bubbles: true, composed: true }); - this.value = name; + this.value = value; this.dispatchEvent(event); } render() { @@ -247,62 +246,41 @@ export class FIconPicker extends FRoot { > - - - - - - - - - - - - + ${this.categories.map(category => { + return html` + + `; + })} - ${Object.entries(defaultIconPacks).map(([name, icons]) => { + ${this.categories.map(category => { return html` - ${name} + ${category.name} - - ${Object.entries(icons).map(([name, svg]) => { + + ${category.icons.map(icon => { return html` this.handleIconSeletion(name, svg)} + @click=${() => this.handleIconSeletion(icon)} padding="small" height="hug-content" - >`; })} `; diff --git a/packages/flow-core/src/components/f-icon/f-icon.ts b/packages/flow-core/src/components/f-icon/f-icon.ts index e776f186a..efee934ea 100644 --- a/packages/flow-core/src/components/f-icon/f-icon.ts +++ b/packages/flow-core/src/components/f-icon/f-icon.ts @@ -17,6 +17,13 @@ import { Subscription } from "rxjs"; injectCss("f-icon", globalStyle); +export type FIconCustomSource = { + name: string; + source: string | URL; +}; + +export type FIconSource = string | FIconCustomSource; + export type FIconState = | "default" | "secondary" @@ -43,7 +50,7 @@ export class FIcon extends FRoot { fill = ""; private _source!: string; - private _originalSource?: string; + private _originalSource?: FIconSource; /** * @internal @@ -57,26 +64,27 @@ export class FIcon extends FRoot { /** * @attribute The small size is the default. */ - @property({ type: String }) + @property({ type: String, reflect: true }) size?: "x-large" | "large" | "medium" | "small" | "x-small" = "small"; /** * @attribute The state of an Icon helps in indicating the degree of emphasis. The Icon component inherits the state from the parent component. By default it is subtle. */ - @property({ type: String }) + @property({ type: String, reflect: true }) state?: FIconState = "default"; /** * @attribute Source property defines what will be displayed on the icon. For icon variant It can take the icon name from a library , any inline SVG or any URL for the image. For emoji, it takes emoji as inline text. */ @property({ - type: String + type: [String, Object], + reflect: true }) get source(): string { return this._source; } // source computed based on value given by user - set source(value) { + set source(value: FIconSource) { this._originalSource = value; this.computeSource(value); } @@ -90,13 +98,13 @@ export class FIcon extends FRoot { /** * @attribute display loader */ - @property({ type: Boolean }) + @property({ type: Boolean, reflect: true }) loading?: boolean = false; /** * @attribute is clickable */ - @property({ type: Boolean }) + @property({ type: Boolean, reflect: true }) clickable?: boolean = false; readonly required = ["source"]; @@ -151,34 +159,43 @@ export class FIcon extends FRoot { return ""; } - computeSource(value: string) { - const emojiRegex = /\p{Extended_Pictographic}/u; - if (isValidHttpUrl(value)) { - this.isURLSource = true; - this._source = ``; - } else if (emojiRegex.test(value)) { - this._source = value; - } else { - const IconPack = configSubject.value.iconPack; - if (IconPack) { - let svg = IconPack[value]; - const theme = configSubject.value.theme; - if (!svg && theme === "f-dark") { - svg = IconPack[value + "-dark"]; - } - if (!svg && theme === "f-light") { - svg = IconPack[value + "-light"]; - } - if (svg) { - this._source = svg; + computeSource(value: FIconSource) { + if (typeof value === "string") { + const emojiRegex = /\p{Extended_Pictographic}/u; + if (isValidHttpUrl(value)) { + this.isURLSource = true; + this._source = ``; + } else if (emojiRegex.test(value)) { + this._source = value; + } else { + const IconPack = configSubject.value.iconPack; + if (IconPack) { + let svg = IconPack[value]; + const theme = configSubject.value.theme; + if (!svg && theme === "f-dark") { + svg = IconPack[value + "-dark"]; + } + if (!svg && theme === "f-light") { + svg = IconPack[value + "-light"]; + } + if (svg) { + this._source = svg; + } else { + this._source = notFound; + } } else { this._source = notFound; } + } + } else if (typeof value === "object") { + if (typeof value.source === "string") { + this._source = value.source; + } else if (value instanceof URL) { + this._source = ``; } else { this._source = notFound; } } - this.requestUpdate(); } render() { diff --git a/stories/flow-core/f-icon-picker.stories.ts b/stories/flow-core/f-icon-picker.stories.ts index c7ad01099..ec29e63ea 100644 --- a/stories/flow-core/f-icon-picker.stories.ts +++ b/stories/flow-core/f-icon-picker.stories.ts @@ -1,3 +1,4 @@ +import { FIconPickerCategories } from "@ollion/flow-core"; import { html } from "lit-html"; export default { @@ -16,10 +17,55 @@ export const Playground = { console.log("input event", e); }; + const categories: FIconPickerCategories = [ + { + name: "System", + categoryIcon: ` + + + + + + + + + + + + + + `, + icons: [ + { + name: "g-kubernetes", + source: `Icon_24px_K8Engine_Color` + }, + { + name: "g-catalog", + source: ` + + + + + + + + + + ` + } + ] + } + ]; + return html` Date: Thu, 15 Feb 2024 16:21:20 +0530 Subject: [PATCH 03/17] FDS-648 custom icon source implemented --- .../src/components/f-icon-button/f-icon-button.ts | 6 +++--- .../src/components/f-icon-picker/f-icon-picker.ts | 11 +++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/flow-core/src/components/f-icon-button/f-icon-button.ts b/packages/flow-core/src/components/f-icon-button/f-icon-button.ts index a2c5858bf..1616bfa81 100644 --- a/packages/flow-core/src/components/f-icon-button/f-icon-button.ts +++ b/packages/flow-core/src/components/f-icon-button/f-icon-button.ts @@ -21,9 +21,9 @@ const variants = ["round", "curved", "block"] as const; const categories = ["fill", "outline", "transparent", "packed"] as const; const sizes = ["large", "medium", "small", "x-small"] as const; -export type FIconButtonVariant = typeof variants[number]; -export type FIconButtonType = typeof categories[number]; -export type FIconButtonSize = typeof sizes[number]; +export type FIconButtonVariant = (typeof variants)[number]; +export type FIconButtonType = (typeof categories)[number]; +export type FIconButtonSize = (typeof sizes)[number]; export type FIconButtonState = | "primary" | "danger" diff --git a/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts index 4e8796bcf..cf05c824a 100644 --- a/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts +++ b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts @@ -14,12 +14,11 @@ injectCss("f-icon-picker", globalStyle); export type FIconPickerState = "primary" | "default" | "success" | "warning" | "danger"; -export type FIconPickerCategories = - | { - name: string; - categoryIcon: string | URL; - icons: FIconCustomSource[]; - }[]; +export type FIconPickerCategories = { + name: string; + categoryIcon: string | URL; + icons: FIconCustomSource[]; +}[]; @customElement("f-icon-picker") export class FIconPicker extends FRoot { /** From cae3f3b600220e6639e74042a73c6ca621ce6ae9 Mon Sep 17 00:00:00 2001 From: vikas-cldcvr Date: Thu, 15 Feb 2024 19:18:48 +0530 Subject: [PATCH 04/17] FDS-648 icon search implemented --- package.json | 11 +- packages/flow-core/package.json | 1 + .../components/f-icon-picker/f-icon-picker.ts | 132 +++++++++++------- .../flow-core/src/components/f-icon/f-icon.ts | 1 + pnpm-lock.yaml | 16 +++ stories/flow-core/f-icon-picker-categories.ts | 68 +++++++++ stories/flow-core/f-icon-picker.stories.ts | 48 +------ 7 files changed, 176 insertions(+), 101 deletions(-) create mode 100644 stories/flow-core/f-icon-picker-categories.ts diff --git a/package.json b/package.json index aa0ee1f62..c800e6a03 100644 --- a/package.json +++ b/package.json @@ -36,9 +36,9 @@ ], "devDependencies": { "@changesets/cli": "^2.25.0", + "@faker-js/faker": "^8.3.1", "@ollion/custom-elements-manifest-to-types": "workspace:*", "@ollion/prettier-config": "^2.1.0", - "@faker-js/faker": "^8.3.1", "@storybook/addon-actions": "^7.5.3", "@storybook/addon-essentials": "^7.5.3", "@storybook/addon-links": "^7.5.3", @@ -47,6 +47,7 @@ "@storybook/blocks": "^7.5.3", "@storybook/web-components": "^7.5.3", "@storybook/web-components-vite": "^7.5.3", + "@types/d3": "7.4.3", "@types/eslint": "^8.4.3", "@types/jest": "29.5.5", "@types/prettier": "^3.0.0", @@ -66,13 +67,13 @@ "sass": "^1.52.3", "storybook": "^7.5.3", "typescript": "^5.2.2", - "vite": "^4.4.11", - "@types/d3": "7.4.3" + "vite": "^4.4.11" }, "dependencies": { "@ollion/flow-aws-icon": "latest", "@ollion/flow-code-editor": "workspace:*", "@ollion/flow-core": "workspace:*", + "@ollion/flow-dashboard": "workspace:*", "@ollion/flow-form-builder": "workspace:*", "@ollion/flow-gcp-icon": "latest", "@ollion/flow-lineage": "workspace:*", @@ -81,10 +82,10 @@ "@ollion/flow-product-icon": "1.14.0", "@ollion/flow-system-icon": "latest", "@ollion/flow-table": "workspace:*", - "@ollion/flow-dashboard": "workspace:*", + "d3": "^7.6.1", "jspdf": "^2.5.1", "lit": "^3.1.0", - "d3": "^7.6.1" + "simple-icons": "^11.4.0" }, "loki": { "configurations": { diff --git a/packages/flow-core/package.json b/packages/flow-core/package.json index 20a30cc53..d6f327b94 100644 --- a/packages/flow-core/package.json +++ b/packages/flow-core/package.json @@ -30,6 +30,7 @@ "axios": "^0.27.2", "emoji-mart": "^5.5.2", "flatpickr": "^4.6.13", + "fuse.js": "^7.0.0", "lit": "^3.1.0", "lodash-es": "^4.17.21", "mark.js": "^8.11.1", diff --git a/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts index cf05c824a..165489e0c 100644 --- a/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts +++ b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts @@ -1,5 +1,5 @@ import { html, unsafeCSS } from "lit"; -import { customElement, property, query, queryAssignedElements } from "lit/decorators.js"; +import { customElement, property, query, queryAssignedElements, state } from "lit/decorators.js"; import { FRoot } from "./../../mixins/components/f-root/f-root"; import globalStyle from "./f-icon-picker-global.scss?inline"; import { injectCss } from "@ollion/flow-core-config"; @@ -10,6 +10,8 @@ import { FText } from "../f-text/f-text"; import { FIcon, FIconCustomSource } from "../f-icon/f-icon"; import { FIconButton } from "../f-icon-button/f-icon-button"; import { FSearch } from "../f-search/f-search"; +import Fuse from "fuse.js"; + injectCss("f-icon-picker", globalStyle); export type FIconPickerState = "primary" | "default" | "success" | "warning" | "danger"; @@ -130,6 +132,9 @@ export class FIconPicker extends FRoot { @query(".f-icon-picker-popover") iconPickerPopover!: FPopover; + @state() + searchKeyword?: string; + clearValue() { /** * @event input @@ -157,6 +162,58 @@ export class FIconPicker extends FRoot { this.value = value; this.dispatchEvent(event); } + + getIconPickerPopover() { + return html` + + + ${this.categories.map(category => { + return html` + + `; + })} + + + + + + ${this.filteredCategories.map(category => { + return html` + ${category.name} + + + ${category.icons.map(icon => { + return html` this.handleIconSeletion(icon)} + padding="small" + height="hug-content" + gap="x-small" + direction="column" + > + `; + })} + `; + })} + + + `; + } render() { /** * clear conditional display @@ -238,58 +295,32 @@ export class FIconPicker extends FRoot { - - - - ${this.categories.map(category => { - return html` - - `; - })} - - - - - - ${this.categories.map(category => { - return html` - ${category.name} - - - ${category.icons.map(icon => { - return html` this.handleIconSeletion(icon)} - padding="small" - height="hug-content" - >`; - })} - `; - })} - - - + ${this.getIconPickerPopover()} `; } + get filteredCategories() { + if (this.searchKeyword && this.searchKeyword.length > 0) { + const filtered = this.categories.map(category => { + const fuse = new Fuse(category.icons, { + keys: ["name", "keywords"], + findAllMatches: true + }); + return { + ...category, + icons: fuse.search(this.searchKeyword as string).map(r => r.item) + }; + }); + return filtered.filter(cat => cat.icons.length > 0); + } + + return this.categories; + } + + handleSearch(e: CustomEvent) { + this.searchKeyword = e.detail.value as string; + } + /** * open/close picker * @param value boolean @@ -297,6 +328,7 @@ export class FIconPicker extends FRoot { toggleIconPicker(value: boolean) { this.iconPickerPopover.target = this.iconPicker; this.iconPickerPopover.open = value; + this.iconPickerPopover.placement = "bottom"; } } diff --git a/packages/flow-core/src/components/f-icon/f-icon.ts b/packages/flow-core/src/components/f-icon/f-icon.ts index efee934ea..2621a8896 100644 --- a/packages/flow-core/src/components/f-icon/f-icon.ts +++ b/packages/flow-core/src/components/f-icon/f-icon.ts @@ -20,6 +20,7 @@ injectCss("f-icon", globalStyle); export type FIconCustomSource = { name: string; source: string | URL; + keywords?: string; }; export type FIconSource = string | FIconCustomSource; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ab99a9760..7cd5d0db2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,6 +53,9 @@ importers: lit: specifier: ^3.1.0 version: 3.1.1 + simple-icons: + specifier: ^11.4.0 + version: 11.4.0 devDependencies: '@changesets/cli': specifier: ^2.25.0 @@ -263,6 +266,9 @@ importers: flatpickr: specifier: ^4.6.13 version: 4.6.13 + fuse.js: + specifier: ^7.0.0 + version: 7.0.0 lit: specifier: ^3.1.0 version: 3.1.1 @@ -9387,6 +9393,11 @@ packages: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true + /fuse.js@7.0.0: + resolution: {integrity: sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==} + engines: {node: '>=10'} + dev: false + /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -13323,6 +13334,11 @@ packages: engines: {node: '>=14'} dev: true + /simple-icons@11.4.0: + resolution: {integrity: sha512-f6Y/+qZk8/+qn8NMdOV80MIFYoW0ulaTmtUunZZXB6Ix/01NKoB7yopMzxeZUWtygCr+l75KKSRQo24Db2h0Ug==} + engines: {node: '>=0.12.18'} + dev: false + /simple-update-notifier@2.0.0: resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} engines: {node: '>=10'} diff --git a/stories/flow-core/f-icon-picker-categories.ts b/stories/flow-core/f-icon-picker-categories.ts new file mode 100644 index 000000000..85448688d --- /dev/null +++ b/stories/flow-core/f-icon-picker-categories.ts @@ -0,0 +1,68 @@ +import { faker } from "@faker-js/faker"; +import { FIconCustomSource, FIconPickerCategories } from "@ollion/flow-core"; + +import * as icons from "simple-icons"; +const categories: FIconPickerCategories = []; +export default function getCategories() { + if (categories.length === 0) { + const allIcons = Object.entries(icons); + for (let i = 0; i < 5; i++) { + const icons: FIconCustomSource[] = []; + const noOfIcons = faker.number.int({ min: 10, max: 100 }); + for (let j = 0; j < noOfIcons; j++) { + const randomIcon = faker.helpers.arrayElement(allIcons); + icons.push({ + name: randomIcon[0], + source: randomIcon[1].svg, + keywords: randomIcon[1].title + }); + } + categories.push({ + name: faker.company.buzzNoun(), + categoryIcon: faker.helpers.arrayElement(allIcons)[1].svg, + icons + }); + } + } + + return categories; +} + +// const getIconName = () => { +// return `${faker.string.fromCharacters( +// "abcdefghijklmnopqrstuxyz" +// )}-${faker.commerce.product()}`.toLocaleLowerCase(); +// }; + +// const categories: FIconPickerCategories = [ +// { +// name: faker.company.buzzNoun(), +// categoryIcon: `StackHawk`, +// icons: [ +// { +// name: getIconName(), +// source: `99designs` +// }, +// { +// name: getIconName(), +// source: `Adobe InDesign` +// } +// ] +// }, +// { +// name: faker.company.buzzNoun(), +// categoryIcon: `Stellar`, +// icons: [ +// { +// name: getIconName(), +// source: `Stryker` +// }, +// { +// name: getIconName(), +// source: `StackBlitz` +// } +// ] +// } +// ]; + +// export const categories; diff --git a/stories/flow-core/f-icon-picker.stories.ts b/stories/flow-core/f-icon-picker.stories.ts index ec29e63ea..6d96250d9 100644 --- a/stories/flow-core/f-icon-picker.stories.ts +++ b/stories/flow-core/f-icon-picker.stories.ts @@ -1,4 +1,4 @@ -import { FIconPickerCategories } from "@ollion/flow-core"; +import getCategories from "./f-icon-picker-categories"; import { html } from "lit-html"; export default { @@ -16,51 +16,7 @@ export const Playground = { const handleInput = (e: CustomEvent) => { console.log("input event", e); }; - - const categories: FIconPickerCategories = [ - { - name: "System", - categoryIcon: ` - - - - - - - - - - - - - - `, - icons: [ - { - name: "g-kubernetes", - source: `Icon_24px_K8Engine_Color` - }, - { - name: "g-catalog", - source: ` - - - - - - - - - - ` - } - ] - } - ]; - + const categories = getCategories(); return html` From c4cb4e443b3f7e5d47a6e92ad846638a4234d5a2 Mon Sep 17 00:00:00 2001 From: vikas-cldcvr Date: Fri, 16 Feb 2024 15:48:56 +0530 Subject: [PATCH 05/17] FDS-648 category selection by scroll and tab click --- .../components/f-icon-picker/f-icon-picker.ts | 101 ++++++++++++++++-- 1 file changed, 94 insertions(+), 7 deletions(-) diff --git a/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts index 165489e0c..da22df9ce 100644 --- a/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts +++ b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts @@ -164,6 +164,15 @@ export class FIconPicker extends FRoot { } getIconPickerPopover() { + const noIconFound = + this.filteredCategories.length === 0 + ? html` + Sorry, no matching icon found for your search. Please try a different search term or + refine your query + ` + : html``; return html` - ${this.categories.map(category => { + ${this.categories.map((category, i) => { return html` this.selectCategory(category.name)} > - + ${this.filteredCategories.map(category => { - return html` + return html` ${category.name} - + ${category.icons.map(icon => { return html``; })} + ${noIconFound} `; @@ -299,12 +330,69 @@ export class FIconPicker extends FRoot { `; } + selectCategory(category: string) { + const iconContainer = this.shadowRoot?.querySelector(".icon-container"); + const categorylabel = this.shadowRoot?.querySelector( + `.category-label[data-category="${category}"]` + ); + + if (iconContainer?.getBoundingClientRect().y === categorylabel?.getBoundingClientRect().y) { + const categoryIcons = this.shadowRoot?.querySelector( + `.category-icons[data-category="${category}"]` + ); + + if (categoryIcons) { + categoryIcons.scrollIntoView({ + block: "start" + }); + + if (iconContainer) { + iconContainer.scrollBy({ + top: -46, + behavior: "smooth" + }); + } + } + } else { + if (categorylabel) { + categorylabel.scrollIntoView({ + block: "start", + behavior: "smooth" + }); + } + } + } + + handleCategorySelection(event: Event) { + const container = event.target as HTMLElement; + const allLabels = container.querySelectorAll(".category-label"); + let lastStickylabel: FDiv | undefined = undefined; + allLabels.forEach(labelElement => { + if (labelElement.getBoundingClientRect().top === container.getBoundingClientRect().top) { + lastStickylabel = labelElement; + } + }); + + if (lastStickylabel) { + const allCatTabs = this.shadowRoot?.querySelectorAll(".category-tab"); + + allCatTabs?.forEach(tab => { + if (tab.dataset.category === lastStickylabel?.dataset.category) { + tab.selected = "notch-bottom"; + } else { + tab.selected = "none"; + } + }); + } + } + get filteredCategories() { if (this.searchKeyword && this.searchKeyword.length > 0) { const filtered = this.categories.map(category => { const fuse = new Fuse(category.icons, { keys: ["name", "keywords"], - findAllMatches: true + findAllMatches: true, + distance: 3 }); return { ...category, @@ -328,7 +416,6 @@ export class FIconPicker extends FRoot { toggleIconPicker(value: boolean) { this.iconPickerPopover.target = this.iconPicker; this.iconPickerPopover.open = value; - this.iconPickerPopover.placement = "bottom"; } } From fc17145e7f2f32f69244cb2f4c7a563895fe97b1 Mon Sep 17 00:00:00 2001 From: vikas-cldcvr Date: Fri, 16 Feb 2024 16:04:29 +0530 Subject: [PATCH 06/17] FDS-648 cleanup --- .../components/f-icon-picker/f-icon-picker.ts | 135 +++++++++++------- 1 file changed, 81 insertions(+), 54 deletions(-) diff --git a/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts index da22df9ce..e2982dd4d 100644 --- a/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts +++ b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts @@ -1,4 +1,4 @@ -import { html, unsafeCSS } from "lit"; +import { html, nothing, unsafeCSS } from "lit"; import { customElement, property, query, queryAssignedElements, state } from "lit/decorators.js"; import { FRoot } from "./../../mixins/components/f-root/f-root"; import globalStyle from "./f-icon-picker-global.scss?inline"; @@ -163,24 +163,31 @@ export class FIconPicker extends FRoot { this.dispatchEvent(event); } - getIconPickerPopover() { - const noIconFound = - this.filteredCategories.length === 0 - ? html` - Sorry, no matching icon found for your search. Please try a different search term or - refine your query - ` - : html``; - return html` - - - ${this.categories.map((category, i) => { + get noIconFound() { + return this.filteredCategories?.length === 0 + ? html` + Sorry, no matching icon found for your search. Please try a different search term or + refine your query + ` + : this.categories + ? html`` + : nothing; + } + + get noCategories() { + return !this.filteredCategories + ? html` + No categories and icons configured. + ` + : nothing; + } + + get categoryTabs() { + return this.categories + ? html` + ${this.categories?.map((category, i) => { return html` `; })} - - + ` + : nothing; + } + + get searchBar() { + return this.filteredCategories + ? html` + ` + : nothing; + } + + get allIcons() { + return this.filteredCategories?.map(category => { + return html` + ${category.name} + + ${category.icons.map(icon => { + return html` this.handleIconSeletion(icon)} + padding="small" + height="hug-content" + gap="x-small" + direction="column" + > + `; + })} + `; + }); + } + + getIconPickerPopover() { + return html` + + ${this.categoryTabs} ${this.searchBar} + - ${this.filteredCategories.map(category => { - return html` - ${category.name} - - - ${category.icons.map(icon => { - return html` this.handleIconSeletion(icon)} - padding="small" - height="hug-content" - gap="x-small" - direction="column" - > - `; - })} - `; - })} - ${noIconFound} + ${this.noCategories} ${this.allIcons} ${this.noIconFound} `; From fac472eeeb35e54df6fac7863fdaa0715cb32a17 Mon Sep 17 00:00:00 2001 From: vikas-cldcvr Date: Fri, 16 Feb 2024 16:27:56 +0530 Subject: [PATCH 07/17] FDS-648 image url examples added --- packages/flow-core/src/components/f-icon/f-icon.ts | 2 +- stories/flow-core/f-icon-picker-categories.ts | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/flow-core/src/components/f-icon/f-icon.ts b/packages/flow-core/src/components/f-icon/f-icon.ts index 2621a8896..eff5ef663 100644 --- a/packages/flow-core/src/components/f-icon/f-icon.ts +++ b/packages/flow-core/src/components/f-icon/f-icon.ts @@ -191,7 +191,7 @@ export class FIcon extends FRoot { } else if (typeof value === "object") { if (typeof value.source === "string") { this._source = value.source; - } else if (value instanceof URL) { + } else if (value.source instanceof URL) { this._source = ``; } else { this._source = notFound; diff --git a/stories/flow-core/f-icon-picker-categories.ts b/stories/flow-core/f-icon-picker-categories.ts index 85448688d..444166ae9 100644 --- a/stories/flow-core/f-icon-picker-categories.ts +++ b/stories/flow-core/f-icon-picker-categories.ts @@ -3,6 +3,15 @@ import { FIconCustomSource, FIconPickerCategories } from "@ollion/flow-core"; import * as icons from "simple-icons"; const categories: FIconPickerCategories = []; + +const categoryIconLinks = [ + "https://cdn3.iconfinder.com/data/icons/logos-brands-3/24/logo_brand_brands_logos_google-1024.png", + "https://cdn3.iconfinder.com/data/icons/logos-brands-3/24/logo_brand_brands_logos_linux-1024.png", + "https://cdn4.iconfinder.com/data/icons/small-n-flat/24/globe-1024.png", + "https://cdn3.iconfinder.com/data/icons/logos-brands-3/24/logo_brand_brands_logos_safari-1024.png", + "https://cdn3.iconfinder.com/data/icons/social-media-2169/24/social_media_social_media_logo_google_wallet-1024.png" +]; +const categoryNames = ["Google", "Linux", "Earth", "Safari", "Media"]; export default function getCategories() { if (categories.length === 0) { const allIcons = Object.entries(icons); @@ -18,8 +27,8 @@ export default function getCategories() { }); } categories.push({ - name: faker.company.buzzNoun(), - categoryIcon: faker.helpers.arrayElement(allIcons)[1].svg, + name: categoryNames[i], //faker.company.buzzNoun(), + categoryIcon: new URL(categoryIconLinks[i]), //faker.helpers.arrayElement(allIcons)[1].svg, icons }); } From 574b50372dd7caafba89a5bb3c6a414c86e37c9f Mon Sep 17 00:00:00 2001 From: vikas-cldcvr Date: Mon, 19 Feb 2024 11:15:26 +0530 Subject: [PATCH 08/17] FDS-648 disabled and close-on-select implemented --- .../f-icon-picker/f-icon-picker-global.scss | 2 +- .../components/f-icon-picker/f-icon-picker.ts | 19 +++++++++++++++++ stories/flow-core/f-icon-picker.stories.ts | 21 ++++++++++++++++--- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/packages/flow-core/src/components/f-icon-picker/f-icon-picker-global.scss b/packages/flow-core/src/components/f-icon-picker/f-icon-picker-global.scss index e4e01e446..c027ce7f5 100644 --- a/packages/flow-core/src/components/f-icon-picker/f-icon-picker-global.scss +++ b/packages/flow-core/src/components/f-icon-picker/f-icon-picker-global.scss @@ -1,7 +1,7 @@ @import "./../../mixins/scss/mixins"; @import "./f-icon-picker-variables"; -f-emoji-picker { +f-icon-picker { display: flex; flex: 1 0 auto; &[disabled] { diff --git a/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts index e2982dd4d..2763e3540 100644 --- a/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts +++ b/packages/flow-core/src/components/f-icon-picker/f-icon-picker.ts @@ -91,6 +91,17 @@ export class FIconPicker extends FRoot { @property({ type: Object }) categories!: FIconPickerCategories; + /** + * @attribute if true close picker popover on value select + */ + @property({ reflect: true, type: Boolean, attribute: "close-on-select" }) + closeOnSelect?: boolean = false; + + // fix for vue2 + set ["close-on-select"](val: boolean) { + this.closeOnSelect = val; + } + readonly required = ["categories"]; /** @@ -160,6 +171,10 @@ export class FIconPicker extends FRoot { composed: true }); this.value = value; + + if (this.closeOnSelect) { + this.closePopOver(); + } this.dispatchEvent(event); } @@ -250,11 +265,15 @@ export class FIconPicker extends FRoot { `; }); } + closePopOver() { + this.iconPickerPopover.open = false; + } getIconPickerPopover() { return html` diff --git a/stories/flow-core/f-icon-picker.stories.ts b/stories/flow-core/f-icon-picker.stories.ts index 6d96250d9..5bddd15ad 100644 --- a/stories/flow-core/f-icon-picker.stories.ts +++ b/stories/flow-core/f-icon-picker.stories.ts @@ -11,12 +11,14 @@ export default { } }; +const categories = getCategories(); + export const Playground = { render: (args: Record) => { const handleInput = (e: CustomEvent) => { console.log("input event", e); }; - const categories = getCategories(); + return html` @@ -293,7 +295,13 @@ export const Flags = { disabled=true - + Label Help! clear=false - + Label Help! close-on-select=true Date: Mon, 19 Feb 2024 11:36:38 +0530 Subject: [PATCH 09/17] FDS-648 custom icon pack creation doc --- .storybook/custom-icon-pack.ts | 5 +++++ .storybook/preview.ts | 3 +++ docs/create-custom-icon-pack.md | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 .storybook/custom-icon-pack.ts create mode 100644 docs/create-custom-icon-pack.md diff --git a/.storybook/custom-icon-pack.ts b/.storybook/custom-icon-pack.ts new file mode 100644 index 000000000..a64720046 --- /dev/null +++ b/.storybook/custom-icon-pack.ts @@ -0,0 +1,5 @@ +const CUSTOM_ICON_PACK: Record = { + apple: `Apple` +}; + +export default CUSTOM_ICON_PACK; diff --git a/.storybook/preview.ts b/.storybook/preview.ts index cc4df8f09..0629fdb9b 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -3,6 +3,7 @@ import SystemIconPack from "@ollion/flow-system-icon/dist/types/icon-pack"; import ProductIconPack from "@ollion/flow-product-icon/dist/types/icon-pack"; import GcpIconPack from "@ollion/flow-gcp-icon/dist/types/icon-pack"; import AwsIconPack from "@ollion/flow-aws-icon/dist/types/icon-pack"; +import CUSTOM_ICON_PACK from "./custom-icon-pack"; import { ConfigUtil } from "@ollion/flow-core-config"; import { changeRoute } from "./utils"; @@ -99,6 +100,8 @@ export const decorators = [ ...AwsIconPack } }); + + ConfigUtil.setConfig({ iconPack: { ...ConfigUtil.getConfig().iconPack, ...CUSTOM_ICON_PACK } }); return html`
= { + apple: `Apple` +}; + +export default CUSTOM_ICON_PACK; +``` + +- **Step 2**: Import the icon pack in your main.ts or whichever is the startup file of your app: + +```typescript +import CUSTOM_ICON_PACK from "./custom-icon-pack"; +``` + +- **Step 3**: Register the icon pack in your app: + +```typescript +import { ConfigUtil } from "@ollion/flow-core-config"; +ConfigUtil.setConfig({ iconPack: { ...ConfigUtil.getConfig().iconPack, ...CUSTOM_ICON_PACK } }); +``` + +- **Step 4**: Use the icon in your HTML: + +```html + +``` From 0b75ed4ddd172647831e0cbc10e0aea0f1eac25f Mon Sep 17 00:00:00 2001 From: vikas-cldcvr Date: Mon, 19 Feb 2024 11:53:18 +0530 Subject: [PATCH 10/17] FDS-648 icon picker categories doc --- docs/create-icon-picker-categories.md | 36 +++++++++++++++++++ .../f-icon-picker-apple-categories.ts | 16 +++++++++ 2 files changed, 52 insertions(+) create mode 100644 docs/create-icon-picker-categories.md create mode 100644 stories/flow-core/f-icon-picker-apple-categories.ts diff --git a/docs/create-icon-picker-categories.md b/docs/create-icon-picker-categories.md new file mode 100644 index 000000000..e1bef422c --- /dev/null +++ b/docs/create-icon-picker-categories.md @@ -0,0 +1,36 @@ +# Creating Icon Picker Categories + +- **Prerequisite**: Ensure that `@ollion/flow-core` is installed in your app. If not, you can visit [here](https://github.com/ollionorg/flow-core?tab=readme-ov-file#existing-project) for installation instructions. + +- **Step 1**: Create a TypeScript file (e.g., `icon-picker-categories.ts`) which exports an object with catgeories and icons. + +```typescript +import { FIconPickerCategories } from "@ollion/flow-core"; +const categories: FIconPickerCategories = []; + +categories.push({ + name: "Apple", + categoryIcon: `Apple`, + icons: [ + { + name: "apple-music", + source: `Apple Music`, + keywords: "apple music" + } + ] +}); + +export default categories; +``` + +- **Step 2**: Import the categories in your component file where you want to use it. + +```typescript +import categories from "./icon-picker-categories"; +``` + +- **Step 3** : Use above catgeories in your app. E.g. in you vue app you can use like below + +```html + +``` diff --git a/stories/flow-core/f-icon-picker-apple-categories.ts b/stories/flow-core/f-icon-picker-apple-categories.ts new file mode 100644 index 000000000..0ba31f647 --- /dev/null +++ b/stories/flow-core/f-icon-picker-apple-categories.ts @@ -0,0 +1,16 @@ +import { FIconPickerCategories } from "@ollion/flow-core"; +const appleCategories: FIconPickerCategories = []; + +appleCategories.push({ + name: "Apple", + categoryIcon: `Apple`, + icons: [ + { + name: "apple-music", + source: `Apple Music`, + keywords: "apple music" + } + ] +}); + +export default appleCategories; From d8ec7b4461163a15129adf10e7ee394b43e318e1 Mon Sep 17 00:00:00 2001 From: Vikas Awaghade <67629551+vikas-cldcvr@users.noreply.github.com> Date: Mon, 19 Feb 2024 11:56:45 +0530 Subject: [PATCH 11/17] Update create-icon-picker-categories.md --- docs/create-icon-picker-categories.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/create-icon-picker-categories.md b/docs/create-icon-picker-categories.md index e1bef422c..4cf324845 100644 --- a/docs/create-icon-picker-categories.md +++ b/docs/create-icon-picker-categories.md @@ -34,3 +34,7 @@ import categories from "./icon-picker-categories"; ```html ``` + +- **Final Output** : + +Screenshot 2024-02-19 at 11 56 06 AM From 56fcca0e89db370b3c193bd981e588a419c3a07c Mon Sep 17 00:00:00 2001 From: Vikas Awaghade <67629551+vikas-cldcvr@users.noreply.github.com> Date: Mon, 19 Feb 2024 11:58:01 +0530 Subject: [PATCH 12/17] Update create-custom-icon-pack.md --- docs/create-custom-icon-pack.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/create-custom-icon-pack.md b/docs/create-custom-icon-pack.md index dfb9f2a76..4463e1a9e 100644 --- a/docs/create-custom-icon-pack.md +++ b/docs/create-custom-icon-pack.md @@ -30,3 +30,7 @@ ConfigUtil.setConfig({ iconPack: { ...ConfigUtil.getConfig().iconPack, ...CUSTOM ```html ``` + +- **Final output** + +Screenshot 2024-02-19 at 11 57 27 AM From b7741dded1daa3ec62339823ec3ef9e1792f4a7f Mon Sep 17 00:00:00 2001 From: vikas-cldcvr Date: Mon, 19 Feb 2024 12:05:27 +0530 Subject: [PATCH 13/17] FDS-648 docs updated --- .storybook/custom-icon-pack.ts | 2 +- docs/create-custom-icon-pack.md | 6 +++++- docs/create-icon-picker-categories.md | 12 ++++++++++-- stories/flow-core/f-icon-picker-apple-categories.ts | 4 ++-- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/.storybook/custom-icon-pack.ts b/.storybook/custom-icon-pack.ts index a64720046..f76d5206b 100644 --- a/.storybook/custom-icon-pack.ts +++ b/.storybook/custom-icon-pack.ts @@ -1,5 +1,5 @@ const CUSTOM_ICON_PACK: Record = { - apple: `Apple` + apple: `` }; export default CUSTOM_ICON_PACK; diff --git a/docs/create-custom-icon-pack.md b/docs/create-custom-icon-pack.md index 4463e1a9e..092c03415 100644 --- a/docs/create-custom-icon-pack.md +++ b/docs/create-custom-icon-pack.md @@ -6,7 +6,11 @@ ```typescript const CUSTOM_ICON_PACK: Record = { - apple: `Apple` + /** + * We can provide url as well like this + * apple : new URL("https://cdn3.iconfinder.com/data/icons/logos-brands-3/24/logo_brand_brands_logos_google-1024.png"); + */ + apple: `` }; export default CUSTOM_ICON_PACK; diff --git a/docs/create-icon-picker-categories.md b/docs/create-icon-picker-categories.md index 4cf324845..5beddbede 100644 --- a/docs/create-icon-picker-categories.md +++ b/docs/create-icon-picker-categories.md @@ -10,11 +10,19 @@ const categories: FIconPickerCategories = []; categories.push({ name: "Apple", - categoryIcon: `Apple`, + /** + * We can provide url as well like this + * categoryIcon : new URL("https://cdn3.iconfinder.com/data/icons/logos-brands-3/24/logo_brand_brands_logos_google-1024.png"); + */ + categoryIcon: ``, icons: [ { name: "apple-music", - source: `Apple Music`, + /** + * We can provide url as well like this + * source : new URL("https://cdn3.iconfinder.com/data/icons/logos-brands-3/24/logo_brand_brands_logos_google-1024.png"); + */ + source: ``, keywords: "apple music" } ] diff --git a/stories/flow-core/f-icon-picker-apple-categories.ts b/stories/flow-core/f-icon-picker-apple-categories.ts index 0ba31f647..a87751ee7 100644 --- a/stories/flow-core/f-icon-picker-apple-categories.ts +++ b/stories/flow-core/f-icon-picker-apple-categories.ts @@ -3,11 +3,11 @@ const appleCategories: FIconPickerCategories = []; appleCategories.push({ name: "Apple", - categoryIcon: `Apple`, + categoryIcon: ``, icons: [ { name: "apple-music", - source: `Apple Music`, + source: ``, keywords: "apple music" } ] From e0c8ae9be23a4acf4a4e99fbd8b62b937241362b Mon Sep 17 00:00:00 2001 From: vikas-cldcvr Date: Mon, 19 Feb 2024 12:07:43 +0530 Subject: [PATCH 14/17] FDS-648 stories updated --- stories/flow-core/f-icon-picker.stories.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stories/flow-core/f-icon-picker.stories.ts b/stories/flow-core/f-icon-picker.stories.ts index 5bddd15ad..7abddde5c 100644 --- a/stories/flow-core/f-icon-picker.stories.ts +++ b/stories/flow-core/f-icon-picker.stories.ts @@ -1,5 +1,6 @@ import getCategories from "./f-icon-picker-categories"; import { html } from "lit-html"; +import appleCategories from "./f-icon-picker-apple-categories"; export default { title: "@ollion/flow-core/f-icon-picker", @@ -115,6 +116,7 @@ export const Variant = { ${variants.map( item => html` Date: Mon, 19 Feb 2024 12:09:15 +0530 Subject: [PATCH 15/17] Update create-icon-picker-categories.md --- docs/create-icon-picker-categories.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/create-icon-picker-categories.md b/docs/create-icon-picker-categories.md index 5beddbede..b54d0894f 100644 --- a/docs/create-icon-picker-categories.md +++ b/docs/create-icon-picker-categories.md @@ -45,4 +45,5 @@ import categories from "./icon-picker-categories"; - **Final Output** : -Screenshot 2024-02-19 at 11 56 06 AM +Screenshot 2024-02-19 at 12 07 07 PM + From 2080b689e696eaa5f90094c57a0128b1005d214c Mon Sep 17 00:00:00 2001 From: vikas-cldcvr Date: Mon, 19 Feb 2024 12:14:52 +0530 Subject: [PATCH 16/17] FDS-648 custom pack icn doc updated --- docs/create-custom-icon-pack.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/create-custom-icon-pack.md b/docs/create-custom-icon-pack.md index 092c03415..8772ef4c3 100644 --- a/docs/create-custom-icon-pack.md +++ b/docs/create-custom-icon-pack.md @@ -6,10 +6,6 @@ ```typescript const CUSTOM_ICON_PACK: Record = { - /** - * We can provide url as well like this - * apple : new URL("https://cdn3.iconfinder.com/data/icons/logos-brands-3/24/logo_brand_brands_logos_google-1024.png"); - */ apple: `` }; @@ -38,3 +34,11 @@ ConfigUtil.setConfig({ iconPack: { ...ConfigUtil.getConfig().iconPack, ...CUSTOM - **Final output** Screenshot 2024-02-19 at 11 57 27 AM + +- **Note**: We can use url of image as well as an icon like below + +```html + +``` From b1ef69d01833d81d35a1c3cef679ffc535cb30e5 Mon Sep 17 00:00:00 2001 From: vikas-cldcvr Date: Mon, 19 Feb 2024 12:15:41 +0530 Subject: [PATCH 17/17] FDS-648 custom pack icn doc updated --- docs/create-icon-picker-categories.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/create-icon-picker-categories.md b/docs/create-icon-picker-categories.md index b54d0894f..897fd543d 100644 --- a/docs/create-icon-picker-categories.md +++ b/docs/create-icon-picker-categories.md @@ -46,4 +46,3 @@ import categories from "./icon-picker-categories"; - **Final Output** : Screenshot 2024-02-19 at 12 07 07 PM -