├── .editorconfig ├── .github ├── dependabot.yml ├── mergeable.yml └── workflows │ ├── Deploy.yml │ ├── PR_Validation.yml │ └── Publish_Site.yml ├── .gitignore ├── .hintrc ├── .nuke ├── build.schema.json └── parameters.json ├── .vscode ├── launch.json └── settings.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── _build.sln ├── _build ├── .editorconfig ├── Build.cs ├── Configuration.cs ├── Directory.Build.props ├── Directory.Build.targets ├── _build.csproj └── _build.csproj.DotSettings ├── build.cmd ├── build.ps1 ├── build.sh ├── global.json ├── lerna.json ├── package-lock.json ├── package.json ├── packages ├── react-library │ ├── .babelrc.json │ ├── .gitignore │ ├── README.md │ ├── lib │ │ ├── components │ │ │ └── stencil-generated │ │ │ │ ├── index.ts │ │ │ │ └── react-component-lib │ │ │ │ ├── attachProps.ts │ │ │ │ ├── case.ts │ │ │ │ ├── createComponent.tsx │ │ │ │ ├── createOverlayComponent.tsx │ │ │ │ ├── dev.ts │ │ │ │ ├── index.ts │ │ │ │ ├── index.tsx │ │ │ │ ├── interfaces.ts │ │ │ │ └── utils │ │ │ │ ├── attachProps.ts │ │ │ │ ├── case.ts │ │ │ │ ├── dev.ts │ │ │ │ └── index.tsx │ │ └── index.ts │ ├── package.json │ └── tsconfig.json └── stencil-library │ ├── .babelrc.json │ ├── .gitignore │ ├── .storybook │ ├── assets │ │ └── DNNLogo.svg │ ├── main.ts │ ├── manager.ts │ ├── preview-head.html │ └── preview.tsx │ ├── README.md │ ├── custom-elements.json │ ├── eslint-plugin │ ├── docs │ │ ├── button-formButtonType-to-type.md │ │ ├── button-type-to-appearance.md │ │ ├── dnn-input-no-disableValidityReporting.md │ │ ├── dnn-modal-no-background-dismiss.md │ │ ├── dnn-searchbox-no-debounced.md │ │ ├── dnn-select-no-disableValidityReporting.md │ │ └── no-label-slot-in-checkbox.md │ ├── package.json │ ├── src │ │ ├── configs │ │ │ └── recommended.ts │ │ ├── index.ts │ │ ├── rules │ │ │ ├── button-formButtonType-to-type.test.ts │ │ │ ├── button-formButtonType-to-type.ts │ │ │ ├── dnn-input-no-disableValidityReporting.test.ts │ │ │ ├── dnn-input-no-disableValidityReporting.ts │ │ │ ├── dnn-modal-no-background-dismiss.test.ts │ │ │ ├── dnn-modal-no-background-dismiss.ts │ │ │ ├── dnn-searchbox-no-debounced.test.ts │ │ │ ├── dnn-searchbox-no-debounced.ts │ │ │ ├── dnn-select-no-disableValidityReporting.test.ts │ │ │ ├── dnn-select-no-disableValidityReporting.ts │ │ │ ├── index.ts │ │ │ ├── no-label-slot-in-checkbox.test.ts │ │ │ └── no-label-slot-in-checkbox.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── vitest.config.ts │ ├── eslint.config.ts │ ├── licenses.json │ ├── package.json │ ├── src │ ├── components.d.ts │ ├── components │ │ ├── dnn-autocomplete │ │ │ ├── dnn-autocomplete.scss │ │ │ ├── dnn-autocomplete.stories.ts │ │ │ ├── dnn-autocomplete.tsx │ │ │ ├── readme.md │ │ │ ├── types.ts │ │ │ └── usage │ │ │ │ ├── HTML.md │ │ │ │ └── JSX-TSX.md │ │ ├── dnn-button │ │ │ ├── dnn-button.scss │ │ │ ├── dnn-button.stories.ts │ │ │ ├── dnn-button.tsx │ │ │ ├── readme.md │ │ │ └── usage │ │ │ │ ├── HTML.md │ │ │ │ └── JSX-TSX.md │ │ ├── dnn-checkbox │ │ │ ├── dnn-checkbox.scss │ │ │ ├── dnn-checkbox.stories.ts │ │ │ ├── dnn-checkbox.tsx │ │ │ ├── readme.md │ │ │ ├── types.ts │ │ │ └── usage │ │ │ │ ├── HTML.md │ │ │ │ └── JSX-TSX.md │ │ ├── dnn-chevron │ │ │ ├── dnn-chevron.scss │ │ │ ├── dnn-chevron.stories.ts │ │ │ ├── dnn-chevron.tsx │ │ │ ├── readme.md │ │ │ └── usage │ │ │ │ ├── HTML.md │ │ │ │ └── JSX-TSX.md │ │ ├── dnn-collapsible │ │ │ ├── dnn-collapsible.scss │ │ │ ├── dnn-collapsible.stories.ts │ │ │ ├── dnn-collapsible.tsx │ │ │ ├── readme.md │ │ │ └── usage │ │ │ │ ├── HTML.md │ │ │ │ └── JSX-TSX.md │ │ ├── dnn-color-input │ │ │ ├── dnn-color-info.ts │ │ │ ├── dnn-color-input.scss │ │ │ ├── dnn-color-input.stories.ts │ │ │ ├── dnn-color-input.tsx │ │ │ └── readme.md │ │ ├── dnn-color-picker │ │ │ ├── dnn-color-picker.scss │ │ │ ├── dnn-color-picker.stories.ts │ │ │ ├── dnn-color-picker.tsx │ │ │ ├── readme.md │ │ │ └── usage │ │ │ │ ├── HTML.md │ │ │ │ └── JSX-TSX.md │ │ ├── dnn-dropzone │ │ │ ├── dnn-dropzone.scss │ │ │ ├── dnn-dropzone.stories.ts │ │ │ ├── dnn-dropzone.tsx │ │ │ ├── readme.md │ │ │ └── types.ts │ │ ├── dnn-fieldset │ │ │ ├── dnn-fieldset.scss │ │ │ ├── dnn-fieldset.tsx │ │ │ └── readme.md │ │ ├── dnn-image-cropper │ │ │ ├── CornerType.ts │ │ │ ├── dnn-image-cropper.scss │ │ │ ├── dnn-image-cropper.stories.ts │ │ │ ├── dnn-image-cropper.tsx │ │ │ ├── readme.md │ │ │ └── types.ts │ │ ├── dnn-input │ │ │ ├── dnn-input.scss │ │ │ ├── dnn-input.stories.ts │ │ │ ├── dnn-input.tsx │ │ │ └── readme.md │ │ ├── dnn-modal │ │ │ ├── dnn-modal.scss │ │ │ ├── dnn-modal.stories.ts │ │ │ ├── dnn-modal.tsx │ │ │ └── readme.md │ │ ├── dnn-monaco-editor │ │ │ ├── dnn-monaco-editor.scss │ │ │ ├── dnn-monaco-editor.stories.ts │ │ │ ├── dnn-monaco-editor.tsx │ │ │ ├── readme.md │ │ │ ├── usage │ │ │ │ ├── HTML.md │ │ │ │ └── JSX-TSX.md │ │ │ └── utils │ │ │ │ └── code.utils.ts │ │ ├── dnn-permissions-grid │ │ │ ├── dnn-permissions-grid.scss │ │ │ ├── dnn-permissions-grid.stories.ts │ │ │ ├── dnn-permissions-grid.tsx │ │ │ ├── localization-interface.ts │ │ │ ├── permissions-interface.ts │ │ │ ├── readme.md │ │ │ ├── role-group-interface.ts │ │ │ ├── role-interface.ts │ │ │ └── searched-user-interface.ts │ │ ├── dnn-progress-bar │ │ │ ├── dnn-progress-bar.scss │ │ │ ├── dnn-progress-bar.stories.ts │ │ │ ├── dnn-progress-bar.tsx │ │ │ ├── readme.md │ │ │ └── usage │ │ │ │ ├── HTML.md │ │ │ │ └── JSX-TSX.md │ │ ├── dnn-richtext │ │ │ ├── dnn-richtext.scss │ │ │ ├── dnn-richtext.stories.ts │ │ │ ├── dnn-richtext.tsx │ │ │ └── readme.md │ │ ├── dnn-searchbox │ │ │ ├── dnn-searchbox.scss │ │ │ ├── dnn-searchbox.stories.ts │ │ │ ├── dnn-searchbox.tsx │ │ │ └── readme.md │ │ ├── dnn-select │ │ │ ├── dnn-select.scss │ │ │ ├── dnn-select.stories.ts │ │ │ ├── dnn-select.tsx │ │ │ └── readme.md │ │ ├── dnn-sort-icon │ │ │ ├── dnn-sort-icon.scss │ │ │ ├── dnn-sort-icon.stories.ts │ │ │ ├── dnn-sort-icon.tsx │ │ │ ├── readme.md │ │ │ └── usage │ │ │ │ ├── HTML.md │ │ │ │ └── JSX-TSX.md │ │ ├── dnn-tab │ │ │ ├── dnn-tab.scss │ │ │ ├── dnn-tab.stories.ts │ │ │ ├── dnn-tab.tsx │ │ │ ├── readme.md │ │ │ └── usage │ │ │ │ ├── HTML.md │ │ │ │ └── JSX-TSX.md │ │ ├── dnn-tabs │ │ │ ├── dnn-tabs.scss │ │ │ ├── dnn-tabs.stories.ts │ │ │ ├── dnn-tabs.tsx │ │ │ ├── readme.md │ │ │ └── usage │ │ │ │ ├── HTML.md │ │ │ │ └── JSX-TSX.md │ │ ├── dnn-textarea │ │ │ ├── dnn-textarea.scss │ │ │ ├── dnn-textarea.stories.ts │ │ │ ├── dnn-textarea.tsx │ │ │ └── readme.md │ │ ├── dnn-toggle │ │ │ ├── dnn-toggle.scss │ │ │ ├── dnn-toggle.stories.ts │ │ │ ├── dnn-toggle.tsx │ │ │ ├── readme.md │ │ │ ├── toggle-interface.ts │ │ │ └── usage │ │ │ │ ├── HTML.md │ │ │ │ └── JSX-TSX.md │ │ ├── dnn-treeview-item │ │ │ ├── dnn-treeview-item.scss │ │ │ ├── dnn-treeview-item.stories.ts │ │ │ ├── dnn-treeview-item.tsx │ │ │ └── readme.md │ │ ├── dnn-vertical-overflow-menu │ │ │ ├── dnn-vertical-overflow-menu.scss │ │ │ ├── dnn-vertical-overflow-menu.stories.ts │ │ │ ├── dnn-vertical-overflow-menu.tsx │ │ │ └── readme.md │ │ ├── dnn-vertical-splitview │ │ │ ├── dnn-vertical-splitview.scss │ │ │ ├── dnn-vertical-splitview.stories.ts │ │ │ ├── dnn-vertical-splitview.tsx │ │ │ └── readme.md │ │ └── examples │ │ │ └── dnn-example-form │ │ │ ├── dnn-example-form.scss │ │ │ ├── dnn-example-form.stories.ts │ │ │ ├── dnn-example-form.tsx │ │ │ └── readme.md │ ├── global.d.ts │ ├── index.html │ ├── index.ts │ └── utilities │ │ ├── colorInfo.spec.ts │ │ ├── colorInfo.ts │ │ ├── debounce.ts │ │ ├── dnnServicesFramework.ts │ │ ├── fileUtilities.ts │ │ ├── mouseUtilities.ts │ │ └── stringUtilities.ts │ ├── stencil.config.ts │ ├── tsconfig.json │ ├── types │ └── raw-md.d.ts │ ├── vite.config.ts │ └── vscode-data.json └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | insert_final_newline = false 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | - package-ecosystem: "nuget" 13 | directory: "/_build" 14 | schedule: 15 | interval: "monthly" 16 | -------------------------------------------------------------------------------- /.github/mergeable.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | mergeable: 3 | - when: pull_request.* 4 | validate: 5 | - do: milestone 6 | no_empty: 7 | enabled: true 8 | message: 'A milestone must be assigned to this pull request' 9 | - do: label 10 | no_empty: 11 | enabled: true 12 | message: 'A label must be assigned to this pull request' 13 | - do: description 14 | no_empty: 15 | enabled: true 16 | message: 'A description must be provided' 17 | -------------------------------------------------------------------------------- /.github/workflows/Deploy.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | # 3 | # 4 | # This code was generated. 5 | # 6 | # - To turn off auto-generation set: 7 | # 8 | # [GitHubActions (AutoGenerate = false)] 9 | # 10 | # - To trigger manual generation invoke: 11 | # 12 | # nuke --generate-configuration GitHubActions_Deploy --host GitHubActions 13 | # 14 | # 15 | # ------------------------------------------------------------------------------ 16 | 17 | name: Deploy 18 | 19 | on: 20 | push: 21 | branches: 22 | - main 23 | - master 24 | - 'release/*' 25 | tags: 26 | - 'v*' 27 | 28 | jobs: 29 | ubuntu-latest: 30 | name: ubuntu-latest 31 | runs-on: ubuntu-latest 32 | steps: 33 | - uses: actions/checkout@v4 34 | with: 35 | fetch-depth: 0 36 | - name: 'Run: Deploy' 37 | run: ./build.cmd Deploy 38 | env: 39 | GithubToken: ${{ secrets.GITHUB_TOKEN }} 40 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 41 | -------------------------------------------------------------------------------- /.github/workflows/PR_Validation.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | # 3 | # 4 | # This code was generated. 5 | # 6 | # - To turn off auto-generation set: 7 | # 8 | # [GitHubActions (AutoGenerate = false)] 9 | # 10 | # - To trigger manual generation invoke: 11 | # 12 | # nuke --generate-configuration GitHubActions_PR_Validation --host GitHubActions 13 | # 14 | # 15 | # ------------------------------------------------------------------------------ 16 | 17 | name: PR_Validation 18 | 19 | on: 20 | pull_request: 21 | branches: 22 | - main 23 | - master 24 | - develop 25 | - development 26 | 27 | jobs: 28 | ubuntu-latest: 29 | name: ubuntu-latest 30 | runs-on: ubuntu-latest 31 | steps: 32 | - uses: actions/checkout@v4 33 | with: 34 | fetch-depth: 0 35 | - name: 'Run: Compile' 36 | run: ./build.cmd Compile 37 | env: 38 | GithubToken: ${{ secrets.GITHUB_TOKEN }} 39 | -------------------------------------------------------------------------------- /.github/workflows/Publish_Site.yml: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | # 3 | # 4 | # This code was generated. 5 | # 6 | # - To turn off auto-generation set: 7 | # 8 | # [GitHubActions (AutoGenerate = false)] 9 | # 10 | # - To trigger manual generation invoke: 11 | # 12 | # nuke --generate-configuration GitHubActions_Publish_Site --host GitHubActions 13 | # 14 | # 15 | # ------------------------------------------------------------------------------ 16 | 17 | name: Publish_Site 18 | 19 | on: 20 | push: 21 | branches: 22 | - main 23 | - master 24 | - 'release/*' 25 | 26 | jobs: 27 | ubuntu-latest: 28 | name: ubuntu-latest 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v4 32 | with: 33 | fetch-depth: 0 34 | - name: 'Run: PublishSite' 35 | run: ./build.cmd PublishSite 36 | env: 37 | GithubToken: ${{ secrets.GITHUB_TOKEN }} 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .nuke/temp/ 3 | .vs/ 4 | _build/bin 5 | _build/obj -------------------------------------------------------------------------------- /.hintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "development" 4 | ], 5 | "hints": { 6 | "axe/name-role-value": "off", 7 | "no-inline-styles": "off", 8 | "axe/aria": "off", 9 | "axe/forms": "off" 10 | } 11 | } -------------------------------------------------------------------------------- /.nuke/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./build.schema.json" 3 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Test eslint rules", 11 | "runtimeExecutable": "npm", 12 | "runtimeArgs": ["run", "test.eslint-plugin"], 13 | "cwd": "${workspaceFolder}/packages/stencil-library", 14 | "console": "integratedTerminal", 15 | "autoAttachChildProcesses": true, 16 | "skipFiles": ["/**", "node_modules/**"], 17 | }, 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules\\typescript\\lib", 3 | "codeQL.githubDatabase.download": "never" 4 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Daniel Valadas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /_build.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31702.278 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "_build\_build.csproj", "{0683E767-54F6-4DBB-AC8F-6E164921B68A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {0683E767-54F6-4DBB-AC8F-6E164921B68A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {0683E767-54F6-4DBB-AC8F-6E164921B68A}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {0683E767-54F6-4DBB-AC8F-6E164921B68A}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {0683E767-54F6-4DBB-AC8F-6E164921B68A}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {4F8CD20F-7448-46F3-86D1-F8598AE93393} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /_build/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | dotnet_style_qualification_for_field = false:warning 3 | dotnet_style_qualification_for_property = false:warning 4 | dotnet_style_qualification_for_method = false:warning 5 | dotnet_style_qualification_for_event = false:warning 6 | dotnet_style_require_accessibility_modifiers = never:warning 7 | 8 | csharp_style_expression_bodied_methods = true:silent 9 | csharp_style_expression_bodied_properties = true:warning 10 | csharp_style_expression_bodied_indexers = true:warning 11 | csharp_style_expression_bodied_accessors = true:warning 12 | -------------------------------------------------------------------------------- /_build/Configuration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | using Nuke.Common.Tooling; 5 | 6 | [TypeConverter(typeof(TypeConverter))] 7 | public class Configuration : Enumeration 8 | { 9 | public static Configuration Debug = new Configuration { Value = nameof(Debug) }; 10 | public static Configuration Release = new Configuration { Value = nameof(Release) }; 11 | 12 | public static implicit operator string(Configuration configuration) 13 | { 14 | return configuration.Value; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /_build/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /_build/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /_build/_build.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net9.0 6 | 7 | CS0649;CS0169 8 | .. 9 | .. 10 | 1 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | :; set -eo pipefail 2 | :; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) 3 | :; ${SCRIPT_DIR}/build.sh "$@" 4 | :; exit $? 5 | 6 | @ECHO OFF 7 | powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %* 8 | -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | Param( 3 | [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] 4 | [string[]]$BuildArguments 5 | ) 6 | 7 | Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)" 8 | 9 | Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 } 10 | $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent 11 | 12 | ########################################################################### 13 | # CONFIGURATION 14 | ########################################################################### 15 | 16 | $BuildProjectFile = "$PSScriptRoot\_build\_build.csproj" 17 | $TempDirectory = "$PSScriptRoot\\.nuke\temp" 18 | 19 | $DotNetGlobalFile = "$PSScriptRoot\\global.json" 20 | $DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1" 21 | $DotNetChannel = "STS" 22 | 23 | $env:DOTNET_CLI_TELEMETRY_OPTOUT = 1 24 | $env:DOTNET_NOLOGO = 1 25 | 26 | ########################################################################### 27 | # EXECUTION 28 | ########################################################################### 29 | 30 | function ExecSafe([scriptblock] $cmd) { 31 | & $cmd 32 | if ($LASTEXITCODE) { exit $LASTEXITCODE } 33 | } 34 | 35 | # If dotnet CLI is installed globally and it matches requested version, use for execution 36 | if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and ` 37 | $(dotnet --version) -and $LASTEXITCODE -eq 0) { 38 | $env:DOTNET_EXE = (Get-Command "dotnet").Path 39 | } 40 | else { 41 | # Download install script 42 | $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1" 43 | New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null 44 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 45 | (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile) 46 | 47 | # If global.json exists, load expected version 48 | if (Test-Path $DotNetGlobalFile) { 49 | $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json) 50 | if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) { 51 | $DotNetVersion = $DotNetGlobal.sdk.version 52 | } 53 | } 54 | 55 | # Install by channel or version 56 | $DotNetDirectory = "$TempDirectory\dotnet-win" 57 | if (!(Test-Path variable:DotNetVersion)) { 58 | ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath } 59 | } else { 60 | ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath } 61 | } 62 | $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe" 63 | $env:PATH = "$DotNetDirectory;$env:PATH" 64 | } 65 | 66 | Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)" 67 | 68 | if (Test-Path env:NUKE_ENTERPRISE_TOKEN) { 69 | & $env:DOTNET_EXE nuget remove source "nuke-enterprise" > $null 70 | & $env:DOTNET_EXE nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password $env:NUKE_ENTERPRISE_TOKEN > $null 71 | } 72 | 73 | ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet } 74 | ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments } 75 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | bash --version 2>&1 | head -n 1 4 | 5 | set -eo pipefail 6 | SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) 7 | 8 | ########################################################################### 9 | # CONFIGURATION 10 | ########################################################################### 11 | 12 | BUILD_PROJECT_FILE="$SCRIPT_DIR/_build/_build.csproj" 13 | TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp" 14 | 15 | DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json" 16 | DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh" 17 | DOTNET_CHANNEL="STS" 18 | 19 | export DOTNET_CLI_TELEMETRY_OPTOUT=1 20 | export DOTNET_NOLOGO=1 21 | 22 | ########################################################################### 23 | # EXECUTION 24 | ########################################################################### 25 | 26 | function FirstJsonValue { 27 | perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}" 28 | } 29 | 30 | # If dotnet CLI is installed globally and it matches requested version, use for execution 31 | if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then 32 | export DOTNET_EXE="$(command -v dotnet)" 33 | else 34 | # Download install script 35 | DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh" 36 | mkdir -p "$TEMP_DIRECTORY" 37 | curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL" 38 | chmod +x "$DOTNET_INSTALL_FILE" 39 | 40 | # If global.json exists, load expected version 41 | if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then 42 | DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")") 43 | if [[ "$DOTNET_VERSION" == "" ]]; then 44 | unset DOTNET_VERSION 45 | fi 46 | fi 47 | 48 | # Install by channel or version 49 | DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix" 50 | if [[ -z ${DOTNET_VERSION+x} ]]; then 51 | "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path 52 | else 53 | "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path 54 | fi 55 | export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet" 56 | export PATH="$DOTNET_DIRECTORY:$PATH" 57 | fi 58 | 59 | echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)" 60 | 61 | if [[ ! -z ${NUKE_ENTERPRISE_TOKEN+x} && "$NUKE_ENTERPRISE_TOKEN" != "" ]]; then 62 | "$DOTNET_EXE" nuget remove source "nuke-enterprise" &>/dev/null || true 63 | "$DOTNET_EXE" nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password "$NUKE_ENTERPRISE_TOKEN" --store-password-in-clear-text &>/dev/null || true 64 | fi 65 | 66 | "$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet 67 | "$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@" 68 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "9.0.202", 4 | "rollForward": "latestMajor" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "node_modules/lerna/schemas/lerna-schema.json", 3 | "version": "0.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "private": true, 4 | "workspaces": [ 5 | "packages/stencil-library", 6 | "packages/react-library" 7 | ], 8 | "scripts": { 9 | "build": "npx lerna run build", 10 | "test": "npx lerna run test" 11 | }, 12 | "devDependencies": { 13 | "@types/node": "^22.14.0", 14 | "lerna": "^8.0.0", 15 | "typescript": "^5.0.3" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/react-library/.babelrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "sourceType": "unambiguous", 3 | "presets": [ 4 | [ 5 | "@babel/preset-env", 6 | { 7 | "targets": { 8 | "chrome": 100 9 | } 10 | } 11 | ], 12 | "@babel/preset-typescript", 13 | "@babel/preset-react" 14 | ], 15 | "plugins": [] 16 | } -------------------------------------------------------------------------------- /packages/react-library/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | storybook-static/ 4 | -------------------------------------------------------------------------------- /packages/react-library/README.md: -------------------------------------------------------------------------------- 1 | # `dnn-elements-react` 2 | This is a collection of pure web components (custom elements) for use within DNN Platform or custom extensions for DNN. These can even be used in projects outside of the DNN purview, though some are unique for the DNN experience. The web components in `dnn-elements-react` are framework specific to React. For framework agnostic web components, you can use `dnn-elements`. 3 | 4 | ## Usage 5 | ### npm 6 | `npm install @dnncommunity/dnn-elements-react` 7 | 8 | ### yarn 9 | `yarn add @dnncommunity/dnn-elements-react` 10 | 11 | ``` 12 | // App.tsx 13 | import { DnnButton, defineCustomElements } from '@dnncommunity/dnn-elements-react'; 14 | 15 | defineCustomElements(); 16 | 17 | function App() { 18 | return ( 19 |
Secondary Button 21 |
22 | ); 23 | } 24 | ``` -------------------------------------------------------------------------------- /packages/react-library/lib/components/stencil-generated/react-component-lib/case.ts: -------------------------------------------------------------------------------- 1 | export const dashToPascalCase = (str: string) => 2 | str 3 | .toLowerCase() 4 | .split('-') 5 | .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)) 6 | .join(''); 7 | export const camelToDashCase = (str: string) => str.replace(/([A-Z])/g, (m: string) => `-${m[0].toLowerCase()}`); 8 | -------------------------------------------------------------------------------- /packages/react-library/lib/components/stencil-generated/react-component-lib/dev.ts: -------------------------------------------------------------------------------- 1 | export const isDevMode = () => { 2 | return process && process.env && process.env.NODE_ENV === 'development'; 3 | }; 4 | 5 | const warnings: { [key: string]: boolean } = {}; 6 | 7 | export const deprecationWarning = (key: string, message: string) => { 8 | if (isDevMode()) { 9 | if (!warnings[key]) { 10 | console.warn(message); 11 | warnings[key] = true; 12 | } 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /packages/react-library/lib/components/stencil-generated/react-component-lib/index.ts: -------------------------------------------------------------------------------- 1 | export { createReactComponent } from './createComponent'; 2 | export { createOverlayComponent } from './createOverlayComponent'; 3 | -------------------------------------------------------------------------------- /packages/react-library/lib/components/stencil-generated/react-component-lib/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import type { StyleReactProps } from '../interfaces'; 4 | 5 | export type StencilReactExternalProps = PropType & 6 | Omit, 'style'> & 7 | StyleReactProps; 8 | 9 | // This will be replaced with React.ForwardedRef when react-output-target is upgraded to React v17 10 | export type StencilReactForwardedRef = ((instance: T | null) => void) | React.MutableRefObject | null; 11 | 12 | export const setRef = (ref: StencilReactForwardedRef | React.Ref | undefined, value: any) => { 13 | if (typeof ref === 'function') { 14 | ref(value); 15 | } else if (ref != null) { 16 | // Cast as a MutableRef so we can assign current 17 | (ref as React.MutableRefObject).current = value; 18 | } 19 | }; 20 | 21 | export const mergeRefs = ( 22 | ...refs: (StencilReactForwardedRef | React.Ref | undefined)[] 23 | ): React.RefCallback => { 24 | return (value: any) => { 25 | refs.forEach((ref) => { 26 | setRef(ref, value); 27 | }); 28 | }; 29 | }; 30 | 31 | export const createForwardRef = (ReactComponent: any, displayName: string) => { 32 | const forwardRef = ( 33 | props: StencilReactExternalProps, 34 | ref: StencilReactForwardedRef 35 | ) => { 36 | return ; 37 | }; 38 | forwardRef.displayName = displayName; 39 | 40 | return React.forwardRef(forwardRef); 41 | }; 42 | 43 | export const defineCustomElement = (tagName: string, customElement: any) => { 44 | if (customElement !== undefined && typeof customElements !== 'undefined' && !customElements.get(tagName)) { 45 | customElements.define(tagName, customElement); 46 | } 47 | }; 48 | 49 | export * from './attachProps'; 50 | export * from './case'; 51 | -------------------------------------------------------------------------------- /packages/react-library/lib/components/stencil-generated/react-component-lib/interfaces.ts: -------------------------------------------------------------------------------- 1 | // General types important to applications using stencil built components 2 | export interface EventEmitter { 3 | emit: (data?: T) => CustomEvent; 4 | } 5 | 6 | export interface StyleReactProps { 7 | class?: string; 8 | className?: string; 9 | style?: { [key: string]: any }; 10 | } 11 | 12 | export interface OverlayEventDetail { 13 | data?: T; 14 | role?: string; 15 | } 16 | 17 | export interface OverlayInterface { 18 | el: HTMLElement; 19 | animated: boolean; 20 | keyboardClose: boolean; 21 | overlayIndex: number; 22 | presented: boolean; 23 | 24 | enterAnimation?: any; 25 | leaveAnimation?: any; 26 | 27 | didPresent: EventEmitter; 28 | willPresent: EventEmitter; 29 | willDismiss: EventEmitter; 30 | didDismiss: EventEmitter; 31 | 32 | present(): Promise; 33 | dismiss(data?: any, role?: string): Promise; 34 | } 35 | -------------------------------------------------------------------------------- /packages/react-library/lib/components/stencil-generated/react-component-lib/utils/case.ts: -------------------------------------------------------------------------------- 1 | export const dashToPascalCase = (str: string) => 2 | str 3 | .toLowerCase() 4 | .split('-') 5 | .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)) 6 | .join(''); 7 | export const camelToDashCase = (str: string) => str.replace(/([A-Z])/g, (m: string) => `-${m[0].toLowerCase()}`); 8 | -------------------------------------------------------------------------------- /packages/react-library/lib/components/stencil-generated/react-component-lib/utils/dev.ts: -------------------------------------------------------------------------------- 1 | export const isDevMode = () => { 2 | return process && process.env && process.env.NODE_ENV === 'development'; 3 | }; 4 | 5 | const warnings: { [key: string]: boolean } = {}; 6 | 7 | export const deprecationWarning = (key: string, message: string) => { 8 | if (isDevMode()) { 9 | if (!warnings[key]) { 10 | console.warn(message); 11 | warnings[key] = true; 12 | } 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /packages/react-library/lib/components/stencil-generated/react-component-lib/utils/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import type { StyleReactProps } from '../interfaces'; 4 | 5 | export type StencilReactExternalProps = PropType & 6 | Omit, 'style'> & 7 | StyleReactProps; 8 | 9 | // This will be replaced with React.ForwardedRef when react-output-target is upgraded to React v17 10 | export type StencilReactForwardedRef = ((instance: T | null) => void) | React.MutableRefObject | null; 11 | 12 | export const setRef = (ref: StencilReactForwardedRef | React.Ref | undefined, value: any) => { 13 | if (typeof ref === 'function') { 14 | ref(value); 15 | } else if (ref != null) { 16 | // Cast as a MutableRef so we can assign current 17 | (ref as React.MutableRefObject).current = value; 18 | } 19 | }; 20 | 21 | export const mergeRefs = ( 22 | ...refs: (StencilReactForwardedRef | React.Ref | undefined)[] 23 | ): React.RefCallback => { 24 | return (value: any) => { 25 | refs.forEach((ref) => { 26 | setRef(ref, value); 27 | }); 28 | }; 29 | }; 30 | 31 | export const createForwardRef = (ReactComponent: any, displayName: string) => { 32 | const forwardRef = ( 33 | props: StencilReactExternalProps, 34 | ref: StencilReactForwardedRef 35 | ) => { 36 | return ; 37 | }; 38 | forwardRef.displayName = displayName; 39 | 40 | return React.forwardRef(forwardRef); 41 | }; 42 | 43 | export const defineCustomElement = (tagName: string, customElement: any) => { 44 | if (customElement !== undefined && typeof customElements !== 'undefined' && !customElements.get(tagName)) { 45 | customElements.define(tagName, customElement); 46 | } 47 | }; 48 | 49 | export * from './attachProps'; 50 | export * from './case'; 51 | -------------------------------------------------------------------------------- /packages/react-library/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./components/stencil-generated"; 2 | export { defineCustomElements } from "@dnncommunity/dnn-elements/loader"; 3 | 4 | -------------------------------------------------------------------------------- /packages/react-library/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dnncommunity/dnn-elements-react", 3 | "version": "0.26.0-alpha.2", 4 | "description": "Dnn themed custom elements with react wrappers.", 5 | "homepage": "https://github.com/valadas/dnn-elements", 6 | "license": "MIT", 7 | "main": "dist/index.js", 8 | "module": "dist/index.js", 9 | "types": "dist/types/index.d.ts", 10 | "directories": { 11 | "lib": "lib" 12 | }, 13 | "files": [ 14 | "dist" 15 | ], 16 | "publishConfig": { 17 | "access": "public" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/valadas/dnn-elements.git" 22 | }, 23 | "scripts": { 24 | "build": "npm run tsc", 25 | "tsc": "tsc -p ." 26 | }, 27 | "bugs": { 28 | "url": "https://github.com/valadas/dnn-elements/issues" 29 | }, 30 | "dependencies": { 31 | "@dnncommunity/dnn-elements": "*" 32 | }, 33 | "devDependencies": { 34 | "@babel/preset-env": "^7.21.4", 35 | "@babel/preset-react": "^7.18.6", 36 | "@babel/preset-typescript": "^7.21.4", 37 | "@types/react": "^18.0.31", 38 | "prop-types": "^15.8.1", 39 | "react": "^18.2.0", 40 | "react-dom": "^19.1.0", 41 | "typescript": "^5.0.3" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/react-library/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "lib": ["dom", "es2015"], 6 | "module": "es2015", 7 | "moduleResolution": "node", 8 | "target": "es2015", 9 | "skipLibCheck": true, 10 | "jsx": "react", 11 | "allowSyntheticDefaultImports": true, 12 | "declarationDir": "./dist/types" 13 | }, 14 | "include": ["lib"], 15 | "exclude": ["node_modules"] 16 | } -------------------------------------------------------------------------------- /packages/stencil-library/.babelrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "sourceType": "unambiguous", 3 | "presets": [ 4 | [ 5 | "@babel/preset-env", 6 | { 7 | "targets": { 8 | "chrome": 100 9 | } 10 | } 11 | ], 12 | "@babel/preset-typescript", 13 | "@babel/preset-react" 14 | ], 15 | "plugins": [] 16 | } -------------------------------------------------------------------------------- /packages/stencil-library/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | www/ 3 | storybook-static/ 4 | loader/ 5 | tools/ 6 | workers/ 7 | 8 | *~ 9 | *.sw[mnpcod] 10 | *.log 11 | *.lock 12 | *.tmp 13 | *.tmp.* 14 | log.txt 15 | *.sublime-project 16 | *.sublime-workspace 17 | 18 | .stencil/ 19 | .idea/ 20 | .vscode/ 21 | .sass-cache/ 22 | .versions/ 23 | node_modules/ 24 | $RECYCLE.BIN/ 25 | 26 | .DS_Store 27 | Thumbs.db 28 | UserInterfaceState.xcuserstate 29 | .env 30 | 31 | *storybook.log 32 | -------------------------------------------------------------------------------- /packages/stencil-library/.storybook/assets/DNNLogo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /packages/stencil-library/.storybook/main.ts: -------------------------------------------------------------------------------- 1 | import type { StorybookConfig } from '@storybook/web-components-vite'; 2 | import { join, dirname } from "path" 3 | 4 | /** 5 | * This function is used to resolve the absolute path of a package. 6 | * It is needed in projects that use Yarn PnP or are set up within a monorepo. 7 | */ 8 | function getAbsolutePath(value: string): any { 9 | return dirname(require.resolve(join(value, 'package.json'))) 10 | } 11 | const config: StorybookConfig = { 12 | "stories": [ 13 | "../src/**/*.mdx", 14 | "../src/components/**/*.stories.@(js|jsx|mjs|ts|tsx)", 15 | ], 16 | "addons": [ 17 | getAbsolutePath('@storybook/addon-essentials'), 18 | getAbsolutePath('@storybook/addon-a11y'), 19 | ], 20 | "framework": { 21 | "name": getAbsolutePath('@storybook/web-components-vite'), 22 | "options": {} 23 | }, 24 | staticDirs: [{ from: './assets', to: '/assets'}], 25 | }; 26 | export default config; -------------------------------------------------------------------------------- /packages/stencil-library/.storybook/manager.ts: -------------------------------------------------------------------------------- 1 | import {addons} from '@storybook/manager-api'; 2 | import {create} from '@storybook/theming'; 3 | 4 | const theme = create({ 5 | base: 'dark', 6 | 7 | colorPrimary: '#00A7EA', 8 | colorSecondary: '#EC3D47', 9 | 10 | // UI 11 | appBg: '#0b1c24', 12 | appContentBg: '#0e2936', 13 | 14 | // Typography 15 | fontBase: '"Muli", sans-serif', 16 | 17 | // Text colors 18 | textColor: '#a9a9a9', 19 | textInverseColor: '#ffffff', 20 | 21 | // Toolbar default and active colors 22 | barTextColor: '#edeef7', 23 | barSelectedColor: '#00A7EA', 24 | barBg: '#191d26', 25 | 26 | // BRAND 27 | brandTitle: 'DNN Elements', 28 | brandImage: 'assets/DNNLogo.svg' 29 | }); 30 | 31 | addons.setConfig({ 32 | enableShortcuts: false, 33 | theme, 34 | sidebar: { 35 | showRoots: true, 36 | }, 37 | toolbar: { 38 | title: { hidden: false }, 39 | zoom: { hidden: true, }, 40 | eject: { hidden: true, }, 41 | copy: { hidden: true, }, 42 | fullscreen: { hidden: true, }, 43 | }, 44 | }); -------------------------------------------------------------------------------- /packages/stencil-library/.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/stencil-library/.storybook/preview.tsx: -------------------------------------------------------------------------------- 1 | // Reverting to .ts as React is no longer part of this version 2 | import type { Preview } from '@storybook/web-components'; 3 | import { setCustomElementsManifest } from '@storybook/web-components'; 4 | import { defineCustomElements } from '../loader'; 5 | import customElements from '../custom-elements.json'; 6 | import { Title, Subtitle, Description, Primary, Controls, Stories } from '@storybook/blocks'; 7 | import React from 'react'; 8 | import { h } from '@stencil/core'; 9 | 10 | // Register Stencil components and set the custom elements manifest 11 | defineCustomElements(); 12 | setCustomElementsManifest(customElements); 13 | 14 | const preview: Preview = { 15 | parameters: { 16 | controls: { 17 | matchers: { 18 | color: /(background|color)$/i, 19 | date: /Date$/i, 20 | }, 21 | }, 22 | tags: ["autodocs"], 23 | docs: { 24 | page: () => ( 25 | [ 26 | , 27 | <Subtitle />, 28 | <Primary />, 29 | <Controls />, 30 | <Stories />, 31 | <Description /> 32 | ] 33 | ), 34 | extractComponentDescription: (component, { notes }) => { 35 | if (notes) { 36 | return typeof notes === 'string' ? notes : notes.markdown || notes.text; 37 | } 38 | return null; 39 | }, 40 | }, 41 | }, 42 | }; 43 | 44 | export default preview; -------------------------------------------------------------------------------- /packages/stencil-library/README.md: -------------------------------------------------------------------------------- 1 | # `dnn-elements` 2 | This is a collection of pure web components (custom elements) for use within DNN Platform or custom extensions for DNN. These can even be used in projects outside of the DNN purview, though some are unique for the DNN experience. The web components in `dnn-elements` are framework agnostic. For framework specific web components (e.g., React), you can use `dnn-elements-<framework>` (currently `dnn-element-react` is the only framework specific version, but there are plans to support Angular soon). 3 | 4 | ## Usage 5 | ### npm 6 | `npm install @dnncommunity/dnn-elements` 7 | 8 | ### yarn 9 | `yarn add @dnncommunity/dnn-elements` 10 | 11 | ``` 12 | // my-component.tsx 13 | import '@dnncommunity/dnn-elements'; 14 | 15 | render() { 16 | return ( 17 | <Host> 18 | <dnn-button type="secondary">Secondary Button</dnn-button> 19 | </Host> 20 | ); 21 | } 22 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/docs/button-formButtonType-to-type.md: -------------------------------------------------------------------------------- 1 | # dnn-button formButtonType obsolete 2 | 3 | **dnn-button** `type` was previously (v0.23 and earlier) to defined the button look. We needed to use `type`. In v0.24 we implemented full support for form integrated components which meant we needed to use this property to represent the type of button (submit, reset, etc.) in a form usage context. A new `appearance` property was recreate to replace the old meaning of type and a new temporary `formButtonType` property was put in place to represent the form button type. In `v0.24` `formButtonType` is now deprecated in favor of the new meaning of the `type` property. 4 | 5 | Example before: 6 | ```html 7 | <dnn-button type="primary" formButtonType="submit">Submit</dnn-button> 8 | ``` 9 | 10 | Example after: 11 | ```html 12 | <dnn-button appearance="primary" type="submit">Submit</dnn-button> 13 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/docs/button-type-to-appearance.md: -------------------------------------------------------------------------------- 1 | # dnn-button type obsolete 2 | 3 | **dnn-button** `type` property will be reused in the future to indicate the form type of button such as `submit` or `reset` or `button`. It has been marked as deprecated but will still work **in only this minor version**. Replace your current usage with the `appearance` prop. For this version only `formButtonType` will be used to indicate the type of form button this is. In the next minor release, `formButtonType` will be dreprecated in favor of the new meaning of `type`. 4 | 5 | Example before: 6 | ```html 7 | <dnn-button type="primary">Submit</dnn-button> 8 | ``` 9 | 10 | Example after: 11 | ```html 12 | <dnn-button appearance="primary" formButtonType="submit">Submit</dnn-button> 13 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/docs/dnn-input-no-disableValidityReporting.md: -------------------------------------------------------------------------------- 1 | # dnn-input disableValidityReporting obsolete 2 | 3 | **dnn-input** `disableValidityReporting` is obsolete. All dnn-elements form components (inputs, buttons, etc.) now operate with a parent form and have their own validity reporting logic that replaces the browser defaults. So there is no longer any logical need to disable the browser default from consumers. 4 | 5 | Example before: 6 | ```html 7 | <dnn-input type="text" required disableValidityReporting /> 8 | ``` 9 | 10 | Example after: 11 | ```html 12 | <dnn-input type="text" required /> 13 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/docs/dnn-modal-no-background-dismiss.md: -------------------------------------------------------------------------------- 1 | # dnn-modal backgroundDismiss obsolete 2 | 3 | **dnn-modal** `backgroundDismiss` is obsolete, use preventBackgroundDismiss instead. 4 | Per html specifications any boolean attribute should have a false default values, this was not the case for this property and it was replaced with the opposite `preventBackgroundDismiss` property instead (so it has the same default UX without breaking html specs). 5 | 6 | Example before: 7 | ```html 8 | <dnn-modal backgroundDimiss={false}> 9 | <p>Something</p> 10 | </dnn-modal> 11 | ``` 12 | 13 | Example after: 14 | ```html 15 | <dnn-modal preventBackgroundDimiss> 16 | <p>Something</p> 17 | </dnn-modal> 18 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/docs/dnn-searchbox-no-debounced.md: -------------------------------------------------------------------------------- 1 | # dnn-searchbox debounce property obsolete 2 | 3 | **dnn-searchbox** `debounce` property is obsolete and debounce can be adjusted or disabled using `debounceTime` instead. 4 | Per html specifications any boolean attribute should have a false default values, this was not the case for this property and it was removed in favor of a more flexible `deboundeTime` property that defaults to 500ms if unspecified. 5 | 6 | Example before: 7 | ```html 8 | <dnn-searchbox debounced={false} /> 9 | ``` 10 | 11 | Example after: 12 | ```html 13 | <dnn-searchbox debounceTime={0} /> 14 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/docs/dnn-select-no-disableValidityReporting.md: -------------------------------------------------------------------------------- 1 | # dnn-select disableValidityReporting obsolete 2 | 3 | **dnn-select** `disableValidityReporting` is obsolete. All dnn-elements form components (inputs, buttons, etc.) now operate with a parent form and have their own validity reporting logic that replaces the browser defaults. So there is no longer any logical need to disable the browser default from consumers. 4 | 5 | Example before: 6 | ```html 7 | <dnn-select required disableValidityReporting> 8 | <option value={}>-- Select an option --</option> 9 | <option value={0}>A</option> 10 | <option value={1}>B</option> 11 | </dnn-select> 12 | ``` 13 | 14 | Example after: 15 | ```html 16 | <dnn-select required> 17 | <option value={}>-- Select an option --</option> 18 | <option value={0}>A</option> 19 | <option value={1}>B</option> 20 | </dnn-select> 21 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/docs/no-label-slot-in-checkbox.md: -------------------------------------------------------------------------------- 1 | # dnn-checkbox should not have any content inside itself 2 | 3 | In earlier versions of dnn-elements, whatever content was inside dnn-checkbox would be pulled automatically into a label for the checkbox. This solution was not great as it prevented flexibility of having positioning between the label and the box or custom styling, etc. It couls also have been a accessibility problem. 4 | 5 | To match the porper accessibility recommendations, this was obsolete and then removed. 6 | 7 | Here is how you can fix old code: 8 | 9 | ## Old 10 | ```jsx 11 | <dnn-checkbox 12 | onChecked={e => console.log(e.detail)} 13 | > 14 | This is my label 15 | </dnn-checkbox> 16 | ``` 17 | 18 | ## New 19 | ```jsx 20 | <label> 21 | <dnn-checkbox onClick={e => console.log(e.detail)} /> 22 | This is my label 23 | </label> 24 | ``` 25 | 26 | You can also have the text before the checkbox if you prefer depending on the desired UI. -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dnncommunity/eslint-plugin-dnn-elements", 3 | "type": "module", 4 | "main": "./dist/index.js", 5 | "exports": { 6 | "import": "./dist/index.js" 7 | }, 8 | "types": "./dist/index.d.ts" 9 | } -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/configs/recommended.ts: -------------------------------------------------------------------------------- 1 | import type { Linter } from "eslint"; 2 | import type { FlatConfig } from "@typescript-eslint/utils/ts-eslint"; 3 | import { rules } from "../rules/index.js"; 4 | 5 | const pluginName = "dnn-elements"; 6 | 7 | const prefixedRules: Linter.RulesRecord = Object.fromEntries( 8 | Object.keys(rules).map(ruleName => [ 9 | `${pluginName}/${ruleName}`, 10 | "error" as const, 11 | ]) 12 | ); 13 | 14 | export const flatRecommended: FlatConfig.Config[] = [ 15 | { 16 | plugins: { 17 | [pluginName]: { 18 | rules, 19 | }, 20 | }, 21 | rules: prefixedRules, 22 | }, 23 | ]; -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import { rules } from "./rules/index.js"; 2 | import { flatRecommended } from "./configs/recommended.js"; 3 | 4 | 5 | const { name, version } = require("../../package.json") as { 6 | name: string; 7 | version: string; 8 | }; 9 | 10 | const plugin = { 11 | meta: { name, version }, 12 | rules, 13 | configs: { 14 | flat: { 15 | recommended: flatRecommended, 16 | } 17 | } 18 | }; 19 | 20 | export default plugin; -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/rules/button-formButtonType-to-type.test.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "@typescript-eslint/rule-tester"; 2 | import * as vitest from "vitest"; 3 | import { rule } from "./button-formButtonType-to-type"; 4 | 5 | RuleTester.afterAll = vitest.afterAll; 6 | RuleTester.it = vitest.it; 7 | RuleTester.itOnly = vitest.it.only; 8 | RuleTester.describe = vitest.describe; 9 | 10 | const ruleTester = new RuleTester(); 11 | 12 | // Define a reusable configuration for JSX parser options 13 | const jsxParserOptions = { 14 | parserOptions: { 15 | ecmaFeatures: { 16 | jsx: true, 17 | }, 18 | }, 19 | }; 20 | 21 | ruleTester.run("button-formButtonType-to-type", rule, { 22 | valid: [ 23 | { 24 | code: "<dnn-button></dnn-button>", 25 | languageOptions: jsxParserOptions, 26 | }, 27 | { 28 | code: "<dnn-button type=\"submit\"></dnn-button>", 29 | languageOptions: jsxParserOptions, 30 | }, 31 | ], 32 | invalid: [ 33 | { 34 | code: "<dnn-button formButtonType=\"submit\"></dnn-button>", 35 | languageOptions: jsxParserOptions, 36 | errors: [{ messageId: "formButtonTypeToType" }], 37 | output: "<dnn-button type=\"submit\"></dnn-button>", 38 | }, 39 | ], 40 | }); -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/rules/button-formButtonType-to-type.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils.js"; 2 | 3 | export const rule = createRule({ 4 | name: "button-formButtonType-to-type", 5 | defaultOptions: [], 6 | meta: { 7 | docs: { 8 | description: "Change formButtonType prop to type in dnn-button", 9 | recommended: true, 10 | url: "https://github.com/DNNCommunity/dnn-elements/releases/tag/v0.27.0", 11 | }, 12 | type: "problem", 13 | fixable: "code", 14 | messages: { 15 | formButtonTypeToType: "formButtonType prop is deprecated. Use type instead.", 16 | }, 17 | schema: [], 18 | }, 19 | create(context) { 20 | return { 21 | JSXElement(node) { 22 | if ( 23 | node.openingElement.name.type === "JSXIdentifier" && 24 | node.openingElement.name.name === "dnn-button" 25 | ) { 26 | for (const attr of node.openingElement.attributes) { 27 | if ( 28 | attr.type === "JSXAttribute" && 29 | attr.name.name === "formButtonType" 30 | ) { 31 | context.report({ 32 | node: attr, 33 | messageId: "formButtonTypeToType", 34 | fix: (fixer) => fixer.replaceText(attr.name, "type"), 35 | }); 36 | } 37 | } 38 | } 39 | } 40 | }; 41 | }, 42 | }); 43 | -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/rules/dnn-input-no-disableValidityReporting.test.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "@typescript-eslint/rule-tester"; 2 | import * as vitest from "vitest"; 3 | import { rule } from "./dnn-input-no-disableValidityReporting"; 4 | 5 | RuleTester.afterAll = vitest.afterAll; 6 | RuleTester.it = vitest.it; 7 | RuleTester.itOnly = vitest.it.only; 8 | RuleTester.describe = vitest.describe; 9 | 10 | const ruleTester = new RuleTester(); 11 | 12 | // Define a reusable configuration for JSX parser options 13 | const jsxParserOptions = { 14 | parserOptions: { 15 | ecmaFeatures: { 16 | jsx: true, 17 | }, 18 | }, 19 | }; 20 | 21 | ruleTester.run("dnn-input-no-disableValidityReporting", rule, { 22 | valid: [ 23 | { 24 | code: "<dnn-input onValueInput={e => console.log(e)} />", 25 | languageOptions: jsxParserOptions, 26 | }, 27 | ], 28 | invalid: [ 29 | { 30 | code: "<dnn-input disableValidityReporting></dnn-input>", 31 | languageOptions: jsxParserOptions, 32 | errors: [{ messageId: "dnnInputNoDisableValidityReporting" }], 33 | output: "<dnn-input ></dnn-input>", 34 | }, 35 | { 36 | code: "<dnn-input disableValidityReporting={true}></dnn-input>", 37 | languageOptions: jsxParserOptions, 38 | errors: [{ messageId: "dnnInputNoDisableValidityReporting" }], 39 | output: "<dnn-input ></dnn-input>", 40 | }, 41 | { 42 | code: "<dnn-input disableValidityReporting={false}></dnn-input>", 43 | languageOptions: jsxParserOptions, 44 | errors: [{ messageId: "dnnInputNoDisableValidityReporting" }], 45 | output: "<dnn-input ></dnn-input>", 46 | }, 47 | ], 48 | }); -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/rules/dnn-input-no-disableValidityReporting.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils.js"; 2 | 3 | export const rule = createRule({ 4 | name: "dnn-input-no-disableValidityReporting", 5 | defaultOptions: [], 6 | meta: { 7 | docs: { 8 | description: "disableValidityReporting is obsolete in dnn-input, no replacement.", 9 | recommended: true, 10 | url: "https://github.com/DNNCommunity/dnn-elements/releases/tag/v0.24.0", 11 | }, 12 | type: "problem", 13 | fixable: "code", 14 | messages: { 15 | dnnInputNoDisableValidityReporting: "disableValidityReporting was remove and the form pattern has it's own built-in validation reporting." 16 | }, 17 | schema: [], 18 | }, 19 | create(context) { 20 | return { 21 | JSXElement(node) { 22 | if ( 23 | node.openingElement.name.type === "JSXIdentifier" && 24 | node.openingElement.name.name === "dnn-input" 25 | ) { 26 | const attribute = node.openingElement.attributes.find(attr => 27 | attr.type === "JSXAttribute" && 28 | attr.name.name === "disableValidityReporting" 29 | ); 30 | 31 | if (attribute?.type === "JSXAttribute") { 32 | context.report({ 33 | node: attribute, 34 | messageId: "dnnInputNoDisableValidityReporting", 35 | fix(fixer) { 36 | return fixer.remove(attribute); 37 | }, 38 | }); 39 | } 40 | } 41 | } 42 | }; 43 | }, 44 | }); 45 | -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/rules/dnn-modal-no-background-dismiss.test.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "@typescript-eslint/rule-tester"; 2 | import * as vitest from "vitest"; 3 | import { rule } from "./dnn-modal-no-background-dismiss"; 4 | 5 | RuleTester.afterAll = vitest.afterAll; 6 | RuleTester.it = vitest.it; 7 | RuleTester.itOnly = vitest.it.only; 8 | RuleTester.describe = vitest.describe; 9 | 10 | const ruleTester = new RuleTester(); 11 | 12 | // Define a reusable configuration for JSX parser options 13 | const jsxParserOptions = { 14 | parserOptions: { 15 | ecmaFeatures: { 16 | jsx: true, 17 | }, 18 | }, 19 | }; 20 | 21 | ruleTester.run("dnn-modal-no-background-dismiss", rule, { 22 | valid: [ 23 | { 24 | code: "<dnn-modal><p>Test</p></dnn-modal>", 25 | languageOptions: jsxParserOptions, 26 | }, 27 | { 28 | code: "<dnn-modal preventBackgdropDismiss></dnn-modal>", 29 | languageOptions: jsxParserOptions, 30 | }, 31 | ], 32 | invalid: [ 33 | { 34 | code: "<dnn-modal backgroundDismiss></dnn-modal>", 35 | languageOptions: jsxParserOptions, 36 | errors: [{ messageId: "dnnModalNoBackgroundDismiss" }], 37 | output: "<dnn-modal ></dnn-modal>", 38 | }, 39 | { 40 | code: "<dnn-modal backgroundDismiss={true}></dnn-modal>", 41 | languageOptions: jsxParserOptions, 42 | errors: [{ messageId: "dnnModalNoBackgroundDismiss" }], 43 | output: "<dnn-modal ></dnn-modal>", 44 | }, 45 | { 46 | code: "<dnn-modal backgroundDismiss={false}></dnn-modal>", 47 | languageOptions: jsxParserOptions, 48 | errors: [{ messageId: "dnnModalNoBackgroundDismiss" }], 49 | output: "<dnn-modal preventBackgroundDismiss></dnn-modal>", 50 | }, 51 | ], 52 | }); -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/rules/dnn-modal-no-background-dismiss.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils.js"; 2 | 3 | export const rule = createRule({ 4 | name: "dnn-modal-no-background-dismiss", 5 | defaultOptions: [], 6 | meta: { 7 | docs: { 8 | description: "Background dismiss is obsolete in dnn-modal", 9 | recommended: true, 10 | url: "https://github.com/DNNCommunity/dnn-elements/releases/tag/v0.24.0", 11 | }, 12 | type: "problem", 13 | fixable: "code", 14 | messages: { 15 | dnnModalNoBackgroundDismiss: "Background dismiss is obsolete in dnn-modal, use preventBackgroundDismiss instead." 16 | }, 17 | schema: [], 18 | }, 19 | create(context) { 20 | return { 21 | JSXElement(node) { 22 | if ( 23 | node.openingElement.name.type === "JSXIdentifier" && 24 | node.openingElement.name.name === "dnn-modal" 25 | ) { 26 | const backgroundDismissAttr = node.openingElement.attributes.find(attr => 27 | attr.type === "JSXAttribute" && 28 | attr.name.name === "backgroundDismiss" 29 | ); 30 | 31 | if (backgroundDismissAttr?.type === "JSXAttribute") { 32 | context.report({ 33 | node: backgroundDismissAttr, 34 | messageId: "dnnModalNoBackgroundDismiss", 35 | fix(fixer) { 36 | const attrValue = backgroundDismissAttr.value; 37 | const isImplicitTrue = !attrValue; 38 | const isExplicitTrue = attrValue && 39 | attrValue.type === "JSXExpressionContainer" && 40 | attrValue.expression.type === "Literal" && 41 | attrValue.expression.value === true; 42 | 43 | const isExplicitFalse = attrValue && 44 | attrValue.type === "JSXExpressionContainer" && 45 | attrValue.expression.type === "Literal" && 46 | attrValue.expression.value === false; 47 | 48 | if (isImplicitTrue || isExplicitTrue) { 49 | // Remove attribute entirely 50 | return fixer.remove(backgroundDismissAttr); 51 | } 52 | 53 | if (isExplicitFalse) { 54 | // Replace with opposite meaning 55 | return fixer.replaceText( 56 | backgroundDismissAttr, 57 | "preventBackgroundDismiss" 58 | ); 59 | } 60 | 61 | // Default behavior: just remove it 62 | return fixer.remove(backgroundDismissAttr); 63 | }, 64 | }); 65 | } 66 | } 67 | } 68 | }; 69 | }, 70 | }); 71 | -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/rules/dnn-searchbox-no-debounced.test.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "@typescript-eslint/rule-tester"; 2 | import * as vitest from "vitest"; 3 | import { rule } from "./dnn-searchbox-no-debounced"; 4 | 5 | RuleTester.afterAll = vitest.afterAll; 6 | RuleTester.it = vitest.it; 7 | RuleTester.itOnly = vitest.it.only; 8 | RuleTester.describe = vitest.describe; 9 | 10 | const ruleTester = new RuleTester(); 11 | 12 | // Define a reusable configuration for JSX parser options 13 | const jsxParserOptions = { 14 | parserOptions: { 15 | ecmaFeatures: { 16 | jsx: true, 17 | }, 18 | }, 19 | }; 20 | 21 | ruleTester.run("dnn-searchbox-no-debounced", rule, { 22 | valid: [ 23 | { 24 | code: "<dnn-searchbox></dnn-searchbox>", 25 | languageOptions: jsxParserOptions, 26 | }, 27 | { 28 | code: "<dnn-searchbox type=\"submit\"></dnn-searchbox>", 29 | languageOptions: jsxParserOptions, 30 | }, 31 | ], 32 | invalid: [ 33 | { 34 | code: "<dnn-searchbox debounced></dnn-searchbox>", 35 | languageOptions: jsxParserOptions, 36 | errors: [{ messageId: "dnnSearchboxNoDebounced" }], 37 | output: "<dnn-searchbox ></dnn-searchbox>", 38 | }, 39 | { 40 | code: "<dnn-searchbox debounced={false}></dnn-searchbox>", 41 | languageOptions: jsxParserOptions, 42 | errors: [{ messageId: "dnnSearchboxNoDebounced" }], 43 | output: "<dnn-searchbox debounceTime={0}></dnn-searchbox>", 44 | }, 45 | ], 46 | }); -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/rules/dnn-select-no-disableValidityReporting.test.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "@typescript-eslint/rule-tester"; 2 | import * as vitest from "vitest"; 3 | import { rule } from "./dnn-select-no-disableValidityReporting"; 4 | 5 | RuleTester.afterAll = vitest.afterAll; 6 | RuleTester.it = vitest.it; 7 | RuleTester.itOnly = vitest.it.only; 8 | RuleTester.describe = vitest.describe; 9 | 10 | const ruleTester = new RuleTester(); 11 | 12 | // Define a reusable configuration for JSX parser options 13 | const jsxParserOptions = { 14 | parserOptions: { 15 | ecmaFeatures: { 16 | jsx: true, 17 | }, 18 | }, 19 | }; 20 | 21 | ruleTester.run("dnn-select-no-disableValidityReporting", rule, { 22 | valid: [ 23 | { 24 | code: "<dnn-select onValueInput={e => console.log(e)} />", 25 | languageOptions: jsxParserOptions, 26 | }, 27 | ], 28 | invalid: [ 29 | { 30 | code: "<dnn-select disableValidityReporting></dnn-select>", 31 | languageOptions: jsxParserOptions, 32 | errors: [{ messageId: "dnnSelectNoDisableValidityReporting" }], 33 | output: "<dnn-select ></dnn-select>", 34 | }, 35 | { 36 | code: "<dnn-select disableValidityReporting={true}></dnn-select>", 37 | languageOptions: jsxParserOptions, 38 | errors: [{ messageId: "dnnSelectNoDisableValidityReporting" }], 39 | output: "<dnn-select ></dnn-select>", 40 | }, 41 | { 42 | code: "<dnn-select disableValidityReporting={false}></dnn-select>", 43 | languageOptions: jsxParserOptions, 44 | errors: [{ messageId: "dnnSelectNoDisableValidityReporting" }], 45 | output: "<dnn-select ></dnn-select>", 46 | }, 47 | ], 48 | }); -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/rules/dnn-select-no-disableValidityReporting.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils.js"; 2 | 3 | export const rule = createRule({ 4 | name: "dnn-select-no-disableValidityReporting", 5 | defaultOptions: [], 6 | meta: { 7 | docs: { 8 | description: "disableValidityReporting is obsolete in dnn-select, no replacement.", 9 | recommended: true, 10 | url: "https://github.com/DNNCommunity/dnn-elements/releases/tag/v0.24.0", 11 | }, 12 | type: "problem", 13 | fixable: "code", 14 | messages: { 15 | dnnSelectNoDisableValidityReporting: "disableValidityReporting was remove and the form pattern has it's own built-in validation reporting." 16 | }, 17 | schema: [], 18 | }, 19 | create(context) { 20 | return { 21 | JSXElement(node) { 22 | if ( 23 | node.openingElement.name.type === "JSXIdentifier" && 24 | node.openingElement.name.name === "dnn-select" 25 | ) { 26 | const attribute = node.openingElement.attributes.find(attr => 27 | attr.type === "JSXAttribute" && 28 | attr.name.name === "disableValidityReporting" 29 | ); 30 | 31 | if (attribute?.type === "JSXAttribute") { 32 | context.report({ 33 | node: attribute, 34 | messageId: "dnnSelectNoDisableValidityReporting", 35 | fix(fixer) { 36 | return fixer.remove(attribute); 37 | }, 38 | }); 39 | } 40 | } 41 | } 42 | }; 43 | }, 44 | }); 45 | -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/rules/index.ts: -------------------------------------------------------------------------------- 1 | import { rule as buttonFormButtonTypeToType } from "./button-formButtonType-to-type.js"; 2 | import { rule as dnnInputNoDisableValidityReporting } from "./dnn-input-no-disableValidityReporting.js"; 3 | import { rule as dnnModalNoBackgroundDismiss} from "./dnn-modal-no-background-dismiss.js" 4 | import { rule as dnnSearchboxNoDebounced } from "./dnn-searchbox-no-debounced.js" 5 | import { rule as dnnSelectNoDisableValidityReporting} from "./dnn-select-no-disableValidityReporting.js" 6 | import { rule as noLabelSlotInCheckbox } from "./no-label-slot-in-checkbox.js"; 7 | 8 | export const rules = { 9 | "button-formButtonType-to-type": buttonFormButtonTypeToType, 10 | "dnn-input-no-disableValidityReporting": dnnInputNoDisableValidityReporting, 11 | "dnn-modal-no-background-dismiss": dnnModalNoBackgroundDismiss, 12 | "dnn-searchbox-no-debounced": dnnSearchboxNoDebounced, 13 | "dnn-select-no-disableValidityReporting": dnnSelectNoDisableValidityReporting, 14 | "no-label-slot-in-checkbox": noLabelSlotInCheckbox, 15 | } -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/rules/no-label-slot-in-checkbox.test.ts: -------------------------------------------------------------------------------- 1 | import { RuleTester } from "@typescript-eslint/rule-tester"; 2 | import * as vitest from "vitest"; 3 | import { rule } from "./no-label-slot-in-checkbox"; 4 | 5 | RuleTester.afterAll = vitest.afterAll; 6 | RuleTester.it = vitest.it; 7 | RuleTester.itOnly = vitest.it.only; 8 | RuleTester.describe = vitest.describe; 9 | 10 | const ruleTester = new RuleTester(); 11 | 12 | // Define a reusable configuration for JSX parser options 13 | const jsxParserOptions = { 14 | parserOptions: { 15 | ecmaFeatures: { 16 | jsx: true, 17 | }, 18 | }, 19 | }; 20 | 21 | ruleTester.run("no-label-slot-in-checkbox", rule, { 22 | valid: [ 23 | { 24 | code: "<dnn-checkbox></dnn-checkbox>", 25 | languageOptions: jsxParserOptions, 26 | }, 27 | { 28 | code: '<dnn-checkbox><div slot="uncheckedicon">Test</div></dnn-checkbox>', 29 | languageOptions: jsxParserOptions, 30 | }, 31 | { 32 | code: [ 33 | "<dnn-checkbox>", 34 | " <div slot=\"uncheckedicon\">unchecked</div>", 35 | " <div slot=\"checkedicon\">checked</div>", 36 | "</dnn-checkbox>", 37 | ].join("\n"), 38 | languageOptions: jsxParserOptions, 39 | } 40 | ], 41 | invalid: [ 42 | { 43 | code: [ 44 | "<dnn-checkbox onClick={e => console.log(e)}>", 45 | " Something", 46 | "</dnn-checkbox>", 47 | ].join("\n"), 48 | languageOptions: jsxParserOptions, 49 | errors: [{ messageId: "noDefaultSlotInCheckbox" }], 50 | }, 51 | { 52 | code: [ 53 | "<dnn-checkbox onClick={e => console.log(e)}>", 54 | " <div slot=\"uncheckedicon\">unchecked</div>", 55 | " Something", 56 | "</dnn-checkbox>", 57 | ].join("\n"), 58 | languageOptions: jsxParserOptions, 59 | errors: [{ messageId: "noDefaultSlotInCheckbox" }], 60 | }, 61 | { 62 | code: [ 63 | "<dnn-checkbox onClick={e => console.log(e)}>", 64 | " <div slot=\"uncheckedicon\">unchecked</div>", 65 | " <p>Something</p>", 66 | "</dnn-checkbox>", 67 | ].join("\n"), 68 | languageOptions: jsxParserOptions, 69 | errors: [{ messageId: "noDefaultSlotInCheckbox" }], 70 | }, 71 | ], 72 | }); 73 | -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/rules/no-label-slot-in-checkbox.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from "../utils.js"; 2 | 3 | export const rule = createRule({ 4 | name: "no-label-slot-in-checkbox", 5 | defaultOptions: [], 6 | meta: { 7 | docs: { 8 | description: "Disallow default slot in dnn-checkbox; all children must have a named slot", 9 | recommended: true, 10 | url: "https://github.com/DNNCommunity/dnn-elements/releases/tag/v0.24.0", 11 | }, 12 | type: "problem", 13 | messages: { 14 | noDefaultSlotInCheckbox: "All children of dnn-checkbox must have a named slot. Default slot is not allowed." 15 | }, 16 | schema: [], 17 | }, 18 | create(context) { 19 | return { 20 | JSXElement(node) { 21 | if ( 22 | node.openingElement.name.type === "JSXIdentifier" && 23 | node.openingElement.name.name === "dnn-checkbox" 24 | ) { 25 | for (const child of node.children) { 26 | if ( 27 | child.type === "JSXText" && child.value.trim() !== "" 28 | ) { 29 | context.report({ 30 | node: child, 31 | messageId: "noDefaultSlotInCheckbox", 32 | }); 33 | } else if ( 34 | child.type === "JSXElement" && 35 | child.openingElement.attributes.every(attr => 36 | !(attr.type === "JSXAttribute" && attr.name.name === "slot") 37 | ) 38 | ) { 39 | context.report({ 40 | node: child, 41 | messageId: "noDefaultSlotInCheckbox", 42 | }); 43 | } 44 | } 45 | } 46 | } 47 | }; 48 | }, 49 | }); 50 | -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { ESLintUtils } from "@typescript-eslint/utils"; 2 | 3 | export interface TypedLintingRuleDocs { 4 | description: string; 5 | recommended?: boolean; 6 | requiresTyepeChecking?: boolean; 7 | }; 8 | 9 | export const createRule = ESLintUtils.RuleCreator<TypedLintingRuleDocs>( 10 | name => `https://github.com/DNNCommunity/dnn-elements/tree/main/packages/stencil-library/eslint-plugin/docs/${name}.md` 11 | ); -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2019", 4 | "module": "NodeNext", 5 | "moduleResolution": "nodenext", 6 | "rootDir": "src", 7 | "outDir": "dist", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "declaration": true, 11 | "skipLibCheck": true, 12 | "types": ["node"], 13 | "forceConsistentCasingInFileNames": true, 14 | "resolveJsonModule": true, 15 | "sourceMap": true, 16 | "inlineSources": true, 17 | "inlineSourceMap": false, 18 | "isolatedModules":true, 19 | "jsx": "react", 20 | "jsxFactory": "h" 21 | }, 22 | "include": ["src/**/*.ts"], 23 | "exclude": ["src/**/*.test.ts"] 24 | } -------------------------------------------------------------------------------- /packages/stencil-library/eslint-plugin/vitest.config.ts: -------------------------------------------------------------------------------- 1 | /// <reference types="vitest" /> 2 | import { defineConfig } from "vitest/config"; 3 | 4 | export default defineConfig({ 5 | test: { 6 | include: ["eslint-plugin/src/**/*.test.ts"], 7 | globals: true, 8 | environment: "node", 9 | } 10 | }) -------------------------------------------------------------------------------- /packages/stencil-library/eslint.config.ts: -------------------------------------------------------------------------------- 1 | import stencil from "@stencil/eslint-plugin"; 2 | import tseslint from "typescript-eslint"; 3 | import eslint from "@eslint/js"; 4 | import dnnElements from "./eslint-plugin"; 5 | import storybook from "eslint-plugin-storybook"; 6 | 7 | export default (tseslint.config( 8 | eslint.configs.recommended, 9 | tseslint.configs.recommendedTypeChecked, 10 | stencil.configs.flat.recommended, 11 | dnnElements.configs.flat.recommended, 12 | storybook.configs["flat/recommended"], 13 | { 14 | files: [ 15 | "src/**/*.{ts,tsx}", 16 | ] 17 | }, 18 | { 19 | files: ['stencil.config.ts'], 20 | languageOptions: { 21 | parser: undefined, 22 | }, 23 | }, 24 | { 25 | ignores: [ 26 | "node_modules/*", 27 | "src/stories/**/*", 28 | "src/**/*.stories.ts", 29 | "src/**/*.stories.tsx", 30 | "dist", 31 | "loader", 32 | "www", 33 | "*.js", 34 | "eslint-plugin/**/*", 35 | "**/*.spec.ts", 36 | ".storybook/**/*", 37 | "storybook-static/**/*", 38 | "eslint.config.ts", 39 | "stencil.config.ts", 40 | "storybook-static", 41 | "types", 42 | "vite.config.ts", 43 | ], 44 | }, 45 | { 46 | languageOptions: { 47 | ecmaVersion: "latest", 48 | sourceType: "module", 49 | parserOptions: { 50 | projectService: true, 51 | project: 'tsconfig.json', 52 | tsconfigRootDir: import.meta.dirname, 53 | }, 54 | }, 55 | }, 56 | { 57 | rules: { 58 | "@typescript-eslint/no-unsafe-return": "off", 59 | "react/jsx-no-bind": "off", 60 | "@typescript-eslint/no-deprecated": "off", 61 | "stencil/strict-boolean-conditions": "off", 62 | "stencil/ban-exported-const-enums": "off", 63 | "@typescript-eslint/no-unsafe-member-access": "off", 64 | "prefer-const": "off", 65 | "no-var": "off", 66 | "@typescript-eslint/no-unnecessary-type-assertion": "off", 67 | "@typescript-eslint/no-unsafe-call": "off", 68 | "@typescript-eslint/no-unsafe-argument": "off", 69 | "@typescript-eslint/no-explicit-any": "off", 70 | "@typescript-eslint/no-unsafe-assignment": "off", 71 | "@typescript-eslint/no-misused-promises": "off", 72 | "@typescript-eslint/no-floating-promises": "off", 73 | "@typescript-eslint/require-await": "off", 74 | "stencil/ban-default-true": "off", 75 | "no-case-declarations": "off", 76 | "@typescript-eslint/no-base-to-string": "off", 77 | "@typescript-eslint/no-unused-vars": "off", 78 | "@typescript-eslint/no-unused-expressions": "off", 79 | "no-fallthrough": "off", 80 | } 81 | }, 82 | )); 83 | -------------------------------------------------------------------------------- /packages/stencil-library/licenses.json: -------------------------------------------------------------------------------- 1 | { 2 | "@dnncommunity/dnn-elements@0.26.0-alpha.2": { 3 | "licenses": "MIT", 4 | "repository": "https://github.com/dnncommunity/dnn-elements", 5 | "path": "", 6 | "licenseFile": "D:\\dnn-elements\\packages\\stencil-library\\README.md" 7 | }, 8 | "react@18.3.1": { 9 | "licenses": "MIT", 10 | "repository": "https://github.com/facebook/react", 11 | "path": "node_modules\\react", 12 | "licenseFile": "D:\\dnn-elements\\packages\\stencil-library\\node_modules\\react\\LICENSE" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-autocomplete/dnn-autocomplete.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: inline-block; 3 | 4 | /** @prop --foreground-color: Defines the foreground color. */ 5 | --foreground-color: var(--dnn-color-foreground, #000); 6 | 7 | /** @prop --background-color: Defines the background color. */ 8 | --background-color: var(--dnn-color-background, #fff); 9 | 10 | /** @prop --focus-color: Defines the color when the component is focused. */ 11 | --focus-color: var(--dnn-color-primary, #3792ED); 12 | 13 | /** @prop --danger-color: Defines the danger color used for invalid data. */ 14 | --danger-color: var(--dnn-color-danger, #900); 15 | 16 | /** @prop --control-radius: Defines the radius for the control corners. */ 17 | --control-radius: var(--dnn-controls-radius, 3px); 18 | } 19 | 20 | dnn-fieldset{ 21 | width: 100%; 22 | } 23 | 24 | @keyframes shift { 25 | 0% { 26 | background-position: 0% 0; 27 | } 28 | 50% { 29 | background-position: 100% 0; 30 | } 31 | 100% { 32 | background-position: 200% 0; 33 | } 34 | } 35 | 36 | .inner-container{ 37 | display: flex; 38 | justify-content: space-between; 39 | position: relative; 40 | width: 100%; 41 | 42 | input { 43 | border: none; 44 | outline: none; 45 | background-color: transparent; 46 | color: var(--foreground-color); 47 | text-align: var(--input-text-align); 48 | width: 100%; 49 | } 50 | 51 | svg.chevron-down{ 52 | height: 1rem; 53 | width: auto; 54 | transform: scale(1.2); 55 | fill: var(--foreground-color); 56 | cursor: pointer; 57 | } 58 | 59 | ul{ 60 | position: absolute; 61 | border: 1px solid lightgray; 62 | margin: 0; 63 | padding: var(--dnn-controls-radius, 3px) 0; 64 | overflow-y: auto; 65 | width: 100%; 66 | box-shadow: 2px 2px 6px 1px rgb(0 0 0 / 30%); 67 | background-color: var(--dnn-color-background, white); 68 | border-radius: var(--dnn-controls-radius, 3px); 69 | z-index: 2; 70 | display: none; 71 | scroll-behavior: smooth; 72 | &.show{ 73 | display: block; 74 | } 75 | li { 76 | display: block; 77 | list-style-type: none; 78 | cursor: pointer; 79 | padding: 0 0.5rem; 80 | &.selected { 81 | background-color: lightgray; 82 | } 83 | &:hover { 84 | background-color: lightgray; 85 | } 86 | } 87 | .loading { 88 | width: 100%; 89 | height: 0.5rem; 90 | border-radius: 0.5rem; 91 | background: linear-gradient( 92 | to right, 93 | var(--background-color) 0%, 94 | var(--foreground-color) 50%, 95 | var(--background-color) 100%); 96 | background-size: 200% 100%; 97 | animation: shift 2s linear infinite; 98 | width: 75%; 99 | margin: 0 auto; 100 | opacity: 0.5; 101 | } 102 | } 103 | } 104 | 105 | dnn-fieldset{ 106 | --fieldset-foreground-color: var(--foreground-color); 107 | --fieldset-background-color: var(--background-color); 108 | --fieldset-focus-color: var(--focus-color); 109 | --fieldset-danger-color: var(--danger-color); 110 | --fieldset-control-radius: var(--control-radius); 111 | } 112 | 113 | svg{ 114 | &.error{ 115 | fill: red; 116 | width: 1em; 117 | height: 1em; 118 | transform: scale(1.5); 119 | margin-right: 0.5em; 120 | } 121 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-autocomplete/dnn-autocomplete.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/web-components'; 2 | import { html } from 'lit'; 3 | import { actions } from '@storybook/addon-actions'; 4 | import readme from "./readme.md?raw"; 5 | 6 | const meta: Meta = { 7 | title: 'Elements/AutoComplete', 8 | component: 'dnn-autocomplete', 9 | tags: ['autodocs'], 10 | parameters: { 11 | docs: { 12 | description: { 13 | component: readme, 14 | } 15 | } 16 | }, 17 | argTypes: { 18 | disabled: { 19 | control: 'boolean', 20 | }, 21 | helpText: { 22 | control: 'text', 23 | }, 24 | label: { 25 | control: 'text', 26 | }, 27 | name: { 28 | control: 'text', 29 | }, 30 | preloadThresholdPixels:{ 31 | control: 'number', 32 | }, 33 | renderSuggestions: { 34 | control: 'object', 35 | }, 36 | required: { 37 | control: 'boolean', 38 | }, 39 | suggestions: { 40 | control: 'object', 41 | }, 42 | totalSuggestions: { 43 | control: 'number', 44 | }, 45 | value: { 46 | control: 'text', 47 | }, 48 | onSearchQueryChanged: { 49 | action: 'onSearchQueryChanged', 50 | } 51 | }, 52 | }; 53 | export default meta; 54 | 55 | const eventsFromNames = actions('itemSelected', 'needMoreItems', 'searchQueryChanged', 'valueChange', 'valueInput'); 56 | 57 | const Template = (args) => 58 | html` 59 | <dnn-autocomplete 60 | .disabled=${args.disabled} 61 | .helpText=${args.helpText} 62 | .label=${args.label} 63 | .name=${args.name} 64 | .preloadThresholdPixels=${args.preloadThresholdPixels} 65 | .renderSuggestions=${args.renderSuggestions} 66 | .required=${args.required} 67 | .suggestions=${args.suggestions} 68 | .totalSuggestions=${args.totalSuggestions} 69 | .value=${args.value} 70 | @itemSelected=${e => eventsFromNames.itemSelected(e)} 71 | @needMoreItems=${e => eventsFromNames.needMoreItems(e)} 72 | @searchQueryChanged=${args.onSearchQueryChanged ? args.onSearchQueryChanged : e => eventsFromNames.searchQueryChanged(e)} 73 | @valueChange=${e => eventsFromNames.valueChange(e)} 74 | @valueInput=${e => eventsFromNames.valueInput(e)} 75 | > 76 | </dnn-autocomplete> 77 | `; 78 | 79 | 80 | type Story = StoryObj; 81 | 82 | export const Primary : Story = Template.bind({}); 83 | Primary.args = { 84 | label: "Autocomplete", 85 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-autocomplete/types.ts: -------------------------------------------------------------------------------- 1 | /** Represents a single autocomplete suggestion */ 2 | export interface DnnAutocompleteSuggestion { 3 | /** That value that represents this entry (must be unique) like an ID. */ 4 | value: string; 5 | 6 | /** The label to display to the user. */ 7 | label: string; 8 | }; 9 | 10 | export interface NeedMoreItemsEventArgs { 11 | /** The current search term. */ 12 | searchTerm: string; 13 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-autocomplete/usage/JSX-TSX.md: -------------------------------------------------------------------------------- 1 | #### Most Basic Usage 2 | ```tsx 3 | const suggestions = 4 | [ 5 | { value: "1", label: "johnsmith" }, 6 | { value: "2", label: "sarahjones" }, 7 | { value: "3", label: "mikeross" }, 8 | { value: "4", label: "emilyclark" }, 9 | { value: "5", label: "davemiller" }, 10 | { value: "6", label: "lindagreen" }, 11 | { value: "7", label: "chrisevans" }, 12 | { value: "8", label: "lisawhite" }, 13 | { value: "9", label: "tomharris" }, 14 | { value: "10", label: "jennymoore" } 15 | ]; 16 | 17 | let filteredSuggestions = suggestions; 18 | 19 | private handleSearchQueryChanged(query){ 20 | if (query == undefined || query == ""){ 21 | this.filteredSuggestions = this.suggestions; 22 | return; 23 | } 24 | this.filteredSuggestions = this.suggestions.filter(user => 25 | user.label.toLowerCase().includes(query.toLowerCase)); 26 | } 27 | 28 | render(){ 29 | return( 30 | <dnn-autocomplete 31 | label="UserName" 32 | suggestions={this.filteredSuggestions} 33 | onSearchQueryChanged={e => this.handleSearchQueryChanged(e.detail)} 34 | /> 35 | ) 36 | } 37 | ``` 38 | 39 | #### Customizing the display of items 40 | ```tsx 41 | private handleRenderSuggestion(suggestion){ 42 | var user = this.getUserDetails(suggestion.value) 43 | return( 44 | <div style="display: flex;"> 45 | <img src=`${user.profilePic}.jpg` /> 46 | <span>{user.firstName} {user.lastName}</span> 47 | </div> 48 | ); 49 | } 50 | 51 | private getUserDetails(userId){ 52 | return // Some logic that returns a user object... 53 | } 54 | 55 | render(){ 56 | return( 57 | <dnn-autocomplete 58 | // Some other props 59 | renderSuggestion={suggestion => this.handleRenderSuggestion(suggestion)} 60 | /> 61 | ); 62 | } 63 | ``` 64 | 65 | #### Using a paging API 66 | ```tsx 67 | let lastFetchedPage = 0; 68 | let totalSuggesitons = 0; 69 | let suggestions = []; 70 | 71 | private handleSearchChanged(query){ 72 | fetch(`https://some.endpoint.com/search/${query}`) 73 | .then(response => response.json()) 74 | .then(data => { 75 | this.lastFetchedPage = 1; 76 | this.totalSuggestion = data.totalResults; 77 | this.suggestions = data.results; 78 | }); 79 | } 80 | 81 | private handleLoadMore(query){ 82 | fetch(`https://some.endpoint.com/search/${query}/page=${this.lastFetchedPage + 1}`) 83 | .then(response => response.json()) 84 | .then(data => { 85 | this.lastFetchedPage++; 86 | this.suggestions = [...this.suggestions, data.results]; 87 | }); 88 | } 89 | 90 | <dnn-autocomplete 91 | suggestions={this.suggestions} 92 | totalSuggestions={this.totalSuggestions} 93 | onSearchQueryChanged={e => { 94 | this.handleSearchChanged(e.detail); 95 | }} 96 | onNeedMoreItems={e => this.loadMore(e.detail.searchTerm)} 97 | /> 98 | ``` 99 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-button/usage/HTML.md: -------------------------------------------------------------------------------- 1 | ```html 2 | <dnn-button 3 | confirm="" 4 | confirm-yes-text="Oh Yeah" 5 | confirm-no-text="No Way" 6 | confirm-message="Are you sure that you're sure that you're sure?" 7 | > 8 | Click me! 9 | </dnn-button> 10 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-button/usage/JSX-TSX.md: -------------------------------------------------------------------------------- 1 | ```tsx 2 | <dnn-button 3 | confirm="" 4 | confirmYesText="Oh Yeah" 5 | confirmNoText="No Way" 6 | confirmMessage="Are you sure that you're sure that you're sure?" 7 | > 8 | Click me! 9 | </dnn-button> 10 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-checkbox/dnn-checkbox.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | /** 3 | * @prop --focus-color: The color to outline the checkbox when hovered or focused, default to the dnn primary color. 4 | */ 5 | --focus-color: var(--dnn-color-primary, #3792ED); 6 | display: inline-flex; 7 | align-items: center; 8 | gap: 0.25rem; 9 | margin: 3px; 10 | } 11 | button{ 12 | cursor: pointer; 13 | background-color: transparent; 14 | border: 0; 15 | padding: 0; 16 | margin: 0; 17 | outline: none; 18 | display: flex; 19 | justify-content: center; 20 | align-items: center; 21 | .unchecked, .checked, .intermediate{ 22 | display: none; 23 | } 24 | &.checked .checked, &.unchecked .unchecked, &.intermediate .intermediate{ 25 | display: block; 26 | } 27 | svg.undefined{ 28 | opacity: 0.45; 29 | cursor: default; 30 | } 31 | &:focus-visible{ 32 | box-shadow: 0 0 2px 2px var(--focus-color); 33 | } 34 | &.invalid{ 35 | border: 2px solid var(--dnn-color-danger); 36 | } 37 | } 38 | label { 39 | cursor: pointer; 40 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-checkbox/dnn-checkbox.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/web-components'; 2 | import { html } from 'lit'; 3 | import { ifDefined } from 'lit-html/directives/if-defined.js'; 4 | import { actions } from '@storybook/addon-actions'; 5 | import readme from "./readme.md?raw"; 6 | 7 | const meta : Meta = { 8 | title: 'Elements/Checkbox', 9 | component: 'dnn-checkbox', 10 | tags: ['autodocs'], 11 | parameters: { 12 | docs: { 13 | description: { 14 | Component: readme, 15 | } 16 | } 17 | }, 18 | argTypes: { 19 | checked: { 20 | options: ['checked', 'unchecked', 'intermediate'], 21 | control: 'radio', 22 | }, 23 | useIntermediate: { 24 | control: 'boolean', 25 | }, 26 | value: { 27 | control: 'text', 28 | }, 29 | required: { 30 | control: 'boolean', 31 | }, 32 | }, 33 | } 34 | 35 | const eventsFromNames = actions("checkedchange"); 36 | 37 | export default meta; 38 | 39 | type Story = StoryObj; 40 | 41 | export const Checkbox : Story = { 42 | args: 43 | { 44 | checked: 'unchecked', 45 | useIntermediate: false, 46 | value: '1', 47 | required: false, 48 | }, 49 | render: (args) => 50 | html` 51 | <dnn-checkbox 52 | checked=${args.checked} 53 | ?use-intermediate=${ifDefined(args.useIntermediate)} 54 | value=${args.value} 55 | ?required=${ifDefined(args.required)} 56 | /> 57 | `, 58 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-checkbox/types.ts: -------------------------------------------------------------------------------- 1 | export type CheckedState = "checked" | "unchecked" | "intermediate"; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-checkbox/usage/HTML.md: -------------------------------------------------------------------------------- 1 | ```html 2 | <dnn-checkbox 3 | checked="unchecked" 4 | name="agree" 5 | value="1" 6 | use-intermediate="false"> 7 | </dnn-checkbox> 8 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-checkbox/usage/JSX-TSX.md: -------------------------------------------------------------------------------- 1 | ```tsx 2 | <dnn-checkbox 3 | checked="unchecked" 4 | name="agree" 5 | value="1" 6 | useIntermediate="false"> 7 | </dnn-checkbox> 8 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-chevron/dnn-chevron.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: inline-block; 3 | } 4 | button{ 5 | cursor: pointer; 6 | border: none; 7 | padding: 0px; 8 | margin: 0px; 9 | min-width: 15px; 10 | min-height: 15px; 11 | display: flex; 12 | justify-content: center; 13 | align-items: center; 14 | background-color: transparent; 15 | } 16 | svg{ 17 | height:2em; 18 | width:2em; 19 | transition: all 300ms ease-in-out; 20 | } 21 | 22 | // FOCUS 23 | button:focus-visible, button:hover{ 24 | svg{ 25 | color: var(--dnn-color-primary); 26 | } 27 | } 28 | 29 | // EXPANDED 30 | :host([expanded]){ 31 | svg{ 32 | transform: rotate(90deg); 33 | } 34 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-chevron/dnn-chevron.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/web-components'; 2 | import { html } from 'lit'; 3 | import { ifDefined } from 'lit-html/directives/if-defined.js'; 4 | import { actions } from '@storybook/addon-actions'; 5 | import readme from "./readme.md?raw"; 6 | 7 | 8 | const meta : Meta = { 9 | title: 'Elements/Chevron', 10 | component: 'dnn-chevron', 11 | tags: ['autodocs'], 12 | parameters: { 13 | docs:{ 14 | description: { 15 | component: readme 16 | } 17 | } 18 | }, 19 | argTypes: { 20 | expandText: { 21 | control: 'text', 22 | }, 23 | collapseText: { 24 | control: 'text', 25 | }, 26 | expanded: { 27 | control: 'boolean', 28 | }, 29 | }, 30 | } 31 | export default meta; 32 | 33 | const eventsFromNames = actions('changed',); 34 | 35 | const Template = (args) => 36 | html` 37 | <dnn-chevron 38 | expand-text=${ifDefined(args.expandText)} 39 | collapse-text=${ifDefined(args.collapseText)} 40 | ?expanded=${ifDefined(args.expanded)}> 41 | </dnn-chevron> 42 | `; 43 | 44 | type Story = StoryObj; 45 | 46 | export const Chevron : Story = Template.bind({}); 47 | Chevron.args = { 48 | expandText: 'expand', 49 | collapseText: 'collapse', 50 | expanded: false, 51 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-chevron/dnn-chevron.tsx: -------------------------------------------------------------------------------- 1 | import { Component, Host, h, Prop, Event, State } from '@stencil/core'; 2 | import { EventEmitter } from '@stencil/core'; 3 | import { Watch } from '@stencil/core'; 4 | 5 | @Component({ 6 | tag: 'dnn-chevron', 7 | styleUrl: 'dnn-chevron.scss', 8 | shadow: true 9 | }) 10 | export class DnnChevron { 11 | 12 | /** Expand text for screen readers */ 13 | @Prop() expandText?: string = "expand"; 14 | 15 | /** Collapse text for screen readers */ 16 | @Prop() collapseText?: string = "collapse"; 17 | 18 | /** Is the chevron expanded */ 19 | @Prop({mutable: true, reflect: true}) expanded?: boolean = false; 20 | @Watch('expanded') 21 | handleExpandedChanged(newValue: boolean) { 22 | this.changed.emit(newValue); 23 | } 24 | 25 | /** Fires up when the expanded status changes */ 26 | @Event() changed!: EventEmitter; 27 | 28 | @State() focused: any; 29 | private button!: HTMLButtonElement; 30 | 31 | render() { 32 | return ( 33 | <Host 34 | tabIndex={this.focused ? -1 : 0} 35 | onFocus={() => this.button.focus()} 36 | onBlur={() => this.button.blur()} 37 | > 38 | <button 39 | ref={el => this.button = el!} 40 | aria-label={this.expanded ? this.collapseText : this.expandText} 41 | onClick={() => this.expanded = !this.expanded} 42 | onFocus={() => this.focused = true} 43 | onBlur={() => this.focused = false} 44 | > 45 | <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg> 46 | </button> 47 | </Host> 48 | ); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-chevron/readme.md: -------------------------------------------------------------------------------- 1 | # dnn-chevron 2 | 3 | 4 | 5 | <!-- Auto Generated Below --> 6 | 7 | 8 | ## Usage 9 | 10 | ### HTML 11 | 12 | ```html 13 | <dnn-chevron 14 | expand-text="expand" 15 | collapse-text="collapse" 16 | expanded="false"> 17 | </dnn-chevron> 18 | ``` 19 | 20 | 21 | ### JSX-TSX 22 | 23 | ```tsx 24 | <dnn-chevron 25 | expandText="expand" 26 | collapseText="collapse" 27 | expanded="false"> 28 | </dnn-chevron> 29 | ``` 30 | 31 | 32 | 33 | ## Properties 34 | 35 | | Property | Attribute | Description | Type | Default | 36 | | -------------- | --------------- | -------------------------------- | ---------------------- | ------------ | 37 | | `collapseText` | `collapse-text` | Collapse text for screen readers | `string \| undefined` | `"collapse"` | 38 | | `expandText` | `expand-text` | Expand text for screen readers | `string \| undefined` | `"expand"` | 39 | | `expanded` | `expanded` | Is the chevron expanded | `boolean \| undefined` | `false` | 40 | 41 | 42 | ## Events 43 | 44 | | Event | Description | Type | 45 | | --------- | ----------------------------------------- | ------------------ | 46 | | `changed` | Fires up when the expanded status changes | `CustomEvent<any>` | 47 | 48 | 49 | ---------------------------------------------- 50 | 51 | *Built with [StencilJS](https://stenciljs.com/)* 52 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-chevron/usage/HTML.md: -------------------------------------------------------------------------------- 1 | ```html 2 | <dnn-chevron 3 | expand-text="expand" 4 | collapse-text="collapse" 5 | expanded="false"> 6 | </dnn-chevron> 7 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-chevron/usage/JSX-TSX.md: -------------------------------------------------------------------------------- 1 | ```tsx 2 | <dnn-chevron 3 | expandText="expand" 4 | collapseText="collapse" 5 | expanded="false"> 6 | </dnn-chevron> 7 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-collapsible/dnn-collapsible.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | } 4 | #container{ 5 | max-height:0; 6 | overflow: hidden; 7 | transition: max-height 300ms ease-in-out; 8 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-collapsible/dnn-collapsible.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/web-components'; 2 | import { html } from 'lit'; 3 | import { ifDefined } from 'lit-html/directives/if-defined.js'; 4 | import { actions } from '@storybook/addon-actions'; 5 | import readme from "./readme.md?raw"; 6 | 7 | const meta: Meta = { 8 | title: "Elements/Collapsible", 9 | component: "dnn-collapsible", 10 | tags: ['autodocs'], 11 | parameters: { 12 | docs: { 13 | description: { 14 | component: readme, 15 | } 16 | } 17 | }, 18 | argTypes: { 19 | expanded: { 20 | type: "boolean", 21 | }, 22 | transitionDuration: { 23 | type: "number", 24 | control: "number", 25 | }, 26 | } 27 | } 28 | export default meta; 29 | 30 | const eventsFromNames = actions('dnnCollapsibleHeightChanged'); 31 | 32 | 33 | 34 | 35 | const Template = (args: { expanded: boolean; transitionDuration: number; }) => { 36 | const chevronOne = document.querySelector('#dnn-chevron1') 37 | 38 | const clickHandler = (e: MouseEvent) => { 39 | const collapsibleOne = document.querySelector('#dnn-collapsible1'); 40 | console.log(collapsibleOne); 41 | 42 | (collapsibleOne as any).expanded = e.detail 43 | } 44 | 45 | return ( 46 | html` 47 | <div class="collapse-row"> 48 | <style type="text/css"> 49 | .collapse-row{ 50 | border: 1px solid grey; 51 | } 52 | .collapse-row .collapse-title{ 53 | display:flex; 54 | align-items: center; 55 | background-color: whitesmoke; 56 | } 57 | .collapse-row .collapse-title>*{ 58 | margin: 10px; 59 | } 60 | </style> 61 | <div class="collapse-title"> 62 | <dnn-chevron @changed=${clickHandler} expanded=${args.expanded} id="dnn-chevron1"></dnn-chevron> 63 | <strong>Collapsible Panel</strong> 64 | </div> 65 | <dnn-collapsible ?expanded=${ifDefined(args.expanded)} id="dnn-collapsible1" transition-duration="300"> 66 | <div id="collapsible-slot-content" style="padding: 15px;"> 67 | <h2>Details</h2> 68 | <p> 69 | Spicy jalapeno bacon ipsum dolor amet bresaola kielbasa doner ham hock biltong, swine shoulder leberkas cupim. Sausage capicola buffalo, tongue jerky frankfurter biltong pork swine landjaeger. Porchetta alcatra burgdoggen beef ribs short ribs corned beef, biltong flank bresaola kielbasa. Ham hock beef kielbasa, cupim cow beef ribs doner. T-bone cow shoulder chuck pastrami. Alcatra pig filet mignon shank. Pancetta shankle meatloaf sausage meatball cupim. 70 | </p> 71 | </div> 72 | </div> 73 | </dnn-collapsible> 74 | </div> 75 | `); 76 | } 77 | 78 | type Story = StoryObj; 79 | 80 | export const Collapsible: Story = Template.bind({}); 81 | Collapsible.args = { 82 | expanded: false, 83 | transitionDuration: 150, 84 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-collapsible/dnn-collapsible.tsx: -------------------------------------------------------------------------------- 1 | import { Component, Host, h, Prop, Element, Event, EventEmitter, Watch, Listen, Method } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: "dnn-collapsible", 5 | styleUrl: "dnn-collapsible.scss", 6 | shadow: true 7 | }) 8 | export class DnnCollapsible { 9 | 10 | @Element() el!: HTMLDnnCollapsibleElement; 11 | 12 | /** Defines if the panel is expanded or not. */ 13 | @Prop({reflect: true}) expanded: boolean = false; 14 | 15 | /** Defines the transition time in ms, defaults to 150ms */ 16 | @Prop() transitionDuration?: number = 150; 17 | 18 | /** Fires whenever the collapsible height has changed */ 19 | @Event({bubbles: true, composed: true}) dnnCollapsibleHeightChanged!: EventEmitter<void>; 20 | 21 | @Listen("dnnCollapsibleHeightChanged") 22 | handleHeightChanged(){ 23 | requestAnimationFrame(() => { 24 | this.updateSize(); 25 | }) 26 | } 27 | 28 | /** 29 | * Updates the component height, use to update after a slot content changes. 30 | */ 31 | @Method() 32 | async updateSize() { 33 | if (this.expanded){ 34 | requestAnimationFrame(() => { 35 | this.container.style.maxHeight = `${this.container.scrollHeight}px`; 36 | }); 37 | setTimeout(() => { 38 | this.container.style.maxHeight = "none"; 39 | }, this.transitionDuration); 40 | } 41 | } 42 | 43 | @Watch("expanded") 44 | handledExpandedChanged(expanded: boolean){ 45 | if (expanded){ 46 | this.updateSize(); 47 | } 48 | else{ 49 | requestAnimationFrame(() => { 50 | this.container.style.maxHeight = `${this.container.scrollHeight}px`; 51 | requestAnimationFrame(() => { 52 | this.container.style.maxHeight = "0px"; 53 | }); 54 | }); 55 | } 56 | setTimeout(() => { 57 | requestAnimationFrame(() => { 58 | this.dnnCollapsibleHeightChanged.emit(); 59 | }); 60 | }, this.transitionDuration); 61 | } 62 | 63 | private container!: HTMLDivElement; 64 | 65 | componentDidLoad() { 66 | this.container.style.transition = `max-height ${this.transitionDuration}ms ease-in-out`; 67 | } 68 | 69 | render() { 70 | return ( 71 | <Host> 72 | <div 73 | id="container" 74 | class={{"expanded": this.expanded}} 75 | ref={el => this.container = el!} 76 | style={{transition: `max-height ${this.transitionDuration}ms ease-in-out`}} 77 | > 78 | <slot></slot> 79 | </div> 80 | </Host> 81 | ); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-collapsible/usage/HTML.md: -------------------------------------------------------------------------------- 1 | ```html 2 | <div class="collapse-row"> 3 | <style type="text/css"> 4 | .collapse-row{ 5 | border: 1px solid grey; 6 | } 7 | .collapse-row .collapse-title{ 8 | display:flex; 9 | align-items: center; 10 | background-color: whitesmoke; 11 | } 12 | .collapse-row .collapse-title>*{ 13 | margin: 10px; 14 | } 15 | </style> 16 | <div class="collapse-title"> 17 | <dnn-chevron id="dnn-chevron1" expanded="false"></dnn-chevron> 18 | <strong>Collapsible Panel</strong> 19 | </div> 20 | <dnn-collapsible id="dnn-collapsible1" expanded="false" transition-duration="300"> 21 | <div id="collapsible-slot-content" style="padding: 15px;"> 22 | <h2>Details</h2> 23 | <p> 24 | Spicy jalapeno bacon ipsum dolor amet bresaola kielbasa doner ham hock biltong, swine shoulder leberkas cupim. Sausage capicola buffalo, tongue jerky frankfurter biltong pork swine landjaeger. Porchetta alcatra burgdoggen beef ribs short ribs corned beef, biltong flank bresaola kielbasa. Ham hock beef kielbasa, cupim cow beef ribs doner. T-bone cow shoulder chuck pastrami. Alcatra pig filet mignon shank. Pancetta shankle meatloaf sausage meatball cupim. 25 | </p> 26 | </div> 27 | </dnn-collapsible> 28 | </div> 29 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-collapsible/usage/JSX-TSX.md: -------------------------------------------------------------------------------- 1 | ```tsx 2 | <div class="collapse-row"> 3 | <style type="text/css"> 4 | .collapse-row{ 5 | border: 1px solid grey; 6 | } 7 | .collapse-row .collapse-title{ 8 | display:flex; 9 | align-items: center; 10 | background-color: whitesmoke; 11 | } 12 | .collapse-row .collapse-title>*{ 13 | margin: 10px; 14 | } 15 | </style> 16 | <div class="collapse-title"> 17 | <dnn-chevron id="dnn-chevron1" expanded="false"></dnn-chevron> 18 | <strong>Collapsible Panel</strong> 19 | </div> 20 | <dnn-collapsible id="dnn-collapsible1" expanded="false" transitionDuration="300"> 21 | <div id="collapsible-slot-content" style="padding: 15px;"> 22 | <h2>Details</h2> 23 | <p> 24 | Spicy jalapeno bacon ipsum dolor amet bresaola kielbasa doner ham hock biltong, swine shoulder leberkas cupim. Sausage capicola buffalo, tongue jerky frankfurter biltong pork swine landjaeger. Porchetta alcatra burgdoggen beef ribs short ribs corned beef, biltong flank bresaola kielbasa. Ham hock beef kielbasa, cupim cow beef ribs doner. T-bone cow shoulder chuck pastrami. Alcatra pig filet mignon shank. Pancetta shankle meatloaf sausage meatball cupim. 25 | </p> 26 | </div> 27 | </dnn-collapsible> 28 | </div> 29 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-color-input/dnn-color-info.ts: -------------------------------------------------------------------------------- 1 | export interface DnnColorInfo { 2 | color: string, 3 | contrastColor: string, 4 | lightColor: string, 5 | darkColor: string 6 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-color-input/dnn-color-input.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: inline-block; 3 | 4 | /** @prop --foreground-color: Defines the foreground color. */ 5 | --foreground-color: var(--dnn-color-foreground, #000); 6 | 7 | /** @prop --background-color: Defines the background color. */ 8 | --background-color: var(--dnn-color-background, #fff); 9 | 10 | /** @prop --focus-color: Defines the color when the component is focused. */ 11 | --focus-color: var(--dnn-color-primary, #3792ED); 12 | 13 | /** @prop --control-radius: Defines the radius for the control corners. */ 14 | --control-radius: var(--dnn-controls-radius, 3px); 15 | 16 | /** @prop --contast-text-align: Allows customizing the text alignment of the contast indicator text. */ 17 | --contast-text-align: left; 18 | } 19 | dnn-fieldset{ 20 | width: 100%; 21 | } 22 | 23 | .inner-container{ 24 | display: flex; 25 | justify-content: space-between; 26 | position: relative; 27 | width: 100%; 28 | background-color: var(--background-color); 29 | } 30 | 31 | button{ 32 | margin: 0 0 0 1em; 33 | padding: 0; 34 | border: none; 35 | background-color: transparent; 36 | width: 1em; 37 | height: 1em; 38 | svg{ 39 | fill: var(--dnn-color-primary); 40 | transform: scale(1.5); 41 | } 42 | } 43 | 44 | .color-preview{ 45 | min-height: 1em; 46 | min-width: 10em; 47 | display: flex; 48 | width: 100%; 49 | position: relative; 50 | >div{ 51 | flex: 1; 52 | } 53 | .contrast{ 54 | position: absolute; 55 | top: 0; 56 | left: 0; 57 | width: 100%; 58 | height: 100%; 59 | display: flex; 60 | justify-content: space-around; 61 | align-items: center; 62 | hr { 63 | min-width: 1em; 64 | border-width: 0.1em 0 0.1em 0; 65 | border-style: solid; 66 | } 67 | } 68 | } 69 | 70 | h3{ 71 | text-align: center; 72 | } 73 | 74 | .modal-content{ 75 | margin: 0.5em; 76 | } 77 | 78 | .controls{ 79 | display: flex; 80 | justify-content: space-between; 81 | margin-top: 1em; 82 | } 83 | 84 | dnn-fieldset{ 85 | --fieldset-foreground-color: var(--foreground-color); 86 | --fieldset-background-color: var(--background-color); 87 | --fieldset-focus-color: var(--focus-color); 88 | --fieldset-danger-color: var(--danger-color); 89 | --fieldset-control-radius: var(--control-radius); 90 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-color-picker/dnn-color-picker.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/web-components'; 2 | import { html } from 'lit'; 3 | import { ifDefined } from 'lit-html/directives/if-defined.js'; 4 | import { actions } from '@storybook/addon-actions'; 5 | import readme from "./readme.md?raw"; 6 | 7 | 8 | const meta: Meta = { 9 | title: 'Elements/Color Picker', 10 | component: 'dnn-color-picker', 11 | tags: ['autodocs'], 12 | parameters: { 13 | docs: { 14 | description: { 15 | component: readme, 16 | } 17 | } 18 | }, 19 | argTypes: { 20 | color: { 21 | control: 'text', 22 | }, 23 | colorBoxHeight: { 24 | control: 'text', 25 | }, 26 | }, 27 | } 28 | 29 | export default meta; 30 | 31 | const eventsFromNames = actions('colorChanged',) 32 | 33 | const Template = (args) => 34 | html` 35 | <dnn-color-picker 36 | color=${ifDefined(args.color)} 37 | color-box-height=${ifDefined(args.colorBoxHeight)}> 38 | </dnn-color-picker> 39 | `; 40 | 41 | type Story = StoryObj; 42 | 43 | export const ColorPicker: Story = Template.bind({}); 44 | ColorPicker.args = { 45 | color: 'FFFFFF', 46 | colorBoxHeight: '50%', 47 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-color-picker/readme.md: -------------------------------------------------------------------------------- 1 | # dnn-color-picker 2 | 3 | 4 | 5 | <!-- Auto Generated Below --> 6 | 7 | 8 | ## Overview 9 | 10 | Color Picker for Dnn 11 | 12 | ## Usage 13 | 14 | ### HTML 15 | 16 | ```html 17 | <dnn-color-picker 18 | color="FFFFFF" 19 | color-box-height="50%" 20 | > 21 | </dnn-color-picker> 22 | ``` 23 | 24 | 25 | ### JSX-TSX 26 | 27 | ```tsx 28 | <dnn-color-picker 29 | color="FFFFFF" 30 | colorBoxHeight="50%" 31 | > 32 | </dnn-color-picker> 33 | ``` 34 | 35 | 36 | 37 | ## Properties 38 | 39 | | Property | Attribute | Description | Type | Default | 40 | | ---------------- | ------------------ | ------------------------------------------------------------------------------------------ | -------- | ---------- | 41 | | `color` | `color` | Sets the initial color, must be a valid 8 character hexadecimal string without the # sign. | `string` | `"FFFFFF"` | 42 | | `colorBoxHeight` | `color-box-height` | Sets the width-height ratio of the color picker saturation-lightness box. | `string` | `"50%"` | 43 | 44 | 45 | ## Events 46 | 47 | | Event | Description | Type | 48 | | -------------- | --------------------------------------------------------------- | ------------------------ | 49 | | `colorChanged` | Fires up when the color is changed and emits a ColorInfo object | `CustomEvent<ColorInfo>` | 50 | 51 | 52 | ## Dependencies 53 | 54 | ### Used by 55 | 56 | - [dnn-color-input](../dnn-color-input) 57 | 58 | ### Graph 59 | ```mermaid 60 | graph TD; 61 | dnn-color-input --> dnn-color-picker 62 | style dnn-color-picker fill:#f9f,stroke:#333,stroke-width:4px 63 | ``` 64 | 65 | ---------------------------------------------- 66 | 67 | *Built with [StencilJS](https://stenciljs.com/)* 68 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-color-picker/usage/HTML.md: -------------------------------------------------------------------------------- 1 | ```html 2 | <dnn-color-picker 3 | color="FFFFFF" 4 | color-box-height="50%" 5 | > 6 | </dnn-color-picker> 7 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-color-picker/usage/JSX-TSX.md: -------------------------------------------------------------------------------- 1 | ```tsx 2 | <dnn-color-picker 3 | color="FFFFFF" 4 | colorBoxHeight="50%" 5 | > 6 | </dnn-color-picker> 7 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-dropzone/dnn-dropzone.scss: -------------------------------------------------------------------------------- 1 | 2 | :host { 3 | /** 4 | * @prop --border-color: The color of the border. 5 | * @prop --border-radius: The radius of the controls borders. 6 | * @prop --drop-background-color: The color of the background when a file is dropping. 7 | */ 8 | --border-color: var(--dnn-color-foreground-light, lightgray); 9 | --border-radius: var(--dnn-controls-radius, 5px); 10 | --drop-background-color: var(--dnn-color-neutral, #b2b2b2); 11 | 12 | display: flex; 13 | flex-direction: column; 14 | gap: 1rem; 15 | text-align: center; 16 | border: 2px dashed var(--border-color); 17 | border-radius: var(--border-radius); 18 | padding: 1rem; 19 | transition: all 300ms ease-in-out; 20 | } 21 | 22 | :host(.dropping){ 23 | background-color: var(--drop-background-color); 24 | } 25 | p{ 26 | margin: 0; 27 | padding: 0; 28 | } 29 | button{ 30 | display: flex; 31 | justify-content: center; 32 | align-items: center; 33 | border: 0px; 34 | margin: 0; 35 | padding: 0; 36 | background-color: transparent; 37 | &:hover{ 38 | cursor: pointer; 39 | } 40 | svg{ 41 | margin-right: 0.5rem; 42 | } 43 | } 44 | label.upload-file{ 45 | display: flex; 46 | justify-content: center; 47 | align-items: center; 48 | cursor: pointer; 49 | input{ 50 | display: none; 51 | } 52 | } 53 | .video-preview{ 54 | display: flex; 55 | flex-direction: column; 56 | align-items: center; 57 | button{ 58 | margin: 1rem; 59 | } 60 | } 61 | .error { 62 | color:red; 63 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-dropzone/dnn-dropzone.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/web-components'; 2 | import { html } from 'lit'; 3 | import { ifDefined } from 'lit-html/directives/if-defined.js'; 4 | import { actions } from '@storybook/addon-actions'; 5 | import readme from "./readme.md?raw"; 6 | 7 | 8 | const meta: Meta = { 9 | title: 'Elements/Dropzone', 10 | component: 'dnn-dropzone', 11 | tags: ['autodocs'], 12 | parameters: { 13 | docs: { 14 | description: { 15 | component: readme, 16 | } 17 | } 18 | }, 19 | argTypes: { 20 | allowedExtensions: { 21 | control: 'text', 22 | }, 23 | allowCameraMode: { 24 | control: 'boolean', 25 | }, 26 | captureQuality: { 27 | options: [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0], 28 | control: 'number', 29 | }, 30 | maxFileSize: { 31 | control: 'number', 32 | } 33 | } 34 | } 35 | export default meta; 36 | 37 | const eventsFromNames = actions('filesSelected', ) 38 | 39 | const resx:{ 40 | dragAndDropFile: string; 41 | capture: string; 42 | or: string; 43 | takePicture: string; 44 | uploadFile: string; 45 | 46 | } = { 47 | dragAndDropFile: "Drag and drop a file", 48 | capture: "Capture", 49 | or: "or", 50 | takePicture: "Take a picture", 51 | uploadFile: "Upload a file", 52 | }; 53 | 54 | const Template = (args) => 55 | html` 56 | <dnn-dropzone 57 | resx=${args.resx} 58 | allowed-extensions=${ifDefined(args.allowedExtensions)} 59 | ?allow-camera-mode=${ifDefined(args.allCameraMode)} 60 | capture-quality=${ifDefined(args.captureQuality)} 61 | max-file-size=${ifDefined(args.maxFileSize)}> 62 | </dnn-dropzone> 63 | `; 64 | 65 | type Story = StoryObj; 66 | 67 | export const Dropzone: Story = Template.bind({}); 68 | Dropzone.args = { 69 | allowedExtensions: 'jpg,jpeg,png,gif', 70 | allowCameraMode: false, 71 | captureQuality: 0.8, 72 | resx, 73 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-dropzone/readme.md: -------------------------------------------------------------------------------- 1 | # dnn-dropzone 2 | 3 | 4 | 5 | <!-- Auto Generated Below --> 6 | 7 | 8 | ## Properties 9 | 10 | | Property | Attribute | Description | Type | Default | 11 | | ------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | ----------- | 12 | | `allowCameraMode` | `allow-camera-mode` | If true, will allow the user to take a snapshot using the device camera. (only works over https). | `boolean` | `false` | 13 | | `allowedExtensions` | `allowed-extensions` | A list of allowed file extensions. If not specified, any file is allowed. Ex: ["jpg", "jpeg", "gif", "png"] | `string[] \| undefined` | `undefined` | 14 | | `captureQuality` | `capture-quality` | Specifies the jpeg quality for when the device camera is used to generate a picture. Needs to be a number between 0 and 1 and defaults to 0.8 | `number` | `0.8` | 15 | | `maxFileSize` | `max-file-size` | Max file size in bytes. | `number \| undefined` | `undefined` | 16 | | `name` | `name` | The name of the field when used in a form. | `string \| undefined` | `undefined` | 17 | | `resx` | `resx` | Localization strings | `DropzoneResx \| undefined` | `undefined` | 18 | 19 | 20 | ## Events 21 | 22 | | Event | Description | Type | 23 | | --------------- | ------------------------------ | --------------------- | 24 | | `filesSelected` | Fires when file were selected. | `CustomEvent<File[]>` | 25 | 26 | 27 | ## CSS Custom Properties 28 | 29 | | Name | Description | 30 | | ------------------------- | ---------------------------------------------------- | 31 | | `--border-color` | The color of the border. | 32 | | `--border-radius` | The radius of the controls borders. | 33 | | `--drop-background-color` | The color of the background when a file is dropping. | 34 | 35 | 36 | ## Dependencies 37 | 38 | ### Used by 39 | 40 | - [dnn-example-form](../examples/dnn-example-form) 41 | - [dnn-image-cropper](../dnn-image-cropper) 42 | 43 | ### Graph 44 | ```mermaid 45 | graph TD; 46 | dnn-example-form --> dnn-dropzone 47 | dnn-image-cropper --> dnn-dropzone 48 | style dnn-dropzone fill:#f9f,stroke:#333,stroke-width:4px 49 | ``` 50 | 51 | ---------------------------------------------- 52 | 53 | *Built with [StencilJS](https://stenciljs.com/)* 54 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-dropzone/types.ts: -------------------------------------------------------------------------------- 1 | export interface DropzoneResx { 2 | /** The title of the control text. */ 3 | dragAndDropFile?: string; 4 | 5 | /** The word used for the picture mode capture button. */ 6 | capture?: string; 7 | 8 | //** The word "or" shown between different control options. */ 9 | or?: string; 10 | 11 | /** The text of the button to take a picture.*/ 12 | takePicture?: string; 13 | 14 | /** The text of the control to pick a file. */ 15 | uploadFile?: string; 16 | 17 | /** The text displayed when attempting to upload a file that is too large. */ 18 | uploadSizeTooLarge?: string; 19 | 20 | /** The information displayed about the filesize limit. 21 | * {0} will be replaced by a human friendly size. (in MB, KB, GB, etc.) */ 22 | fileSizeLimit?: string; 23 | 24 | /** The text displayed when attempting to upload a file type that is not allowed. */ 25 | invalidExtension?: string; 26 | 27 | /** The information displayed about the allowed file extensions. 28 | * {0} will be replaced by a comma separated list of allowed extensions. */ 29 | allowedFileExtensions?: string; 30 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-fieldset/dnn-fieldset.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: inline-block; 3 | 4 | /** @prop --fieldset-foreground-color: Defines the foreground color. */ 5 | --fieldset-foreground-color: var(--dnn-color-foreground, #000); 6 | 7 | /** @prop --fieldset-background-color: Defines the background color. */ 8 | --fieldset-background-color: var(--dnn-color-background, #fff); 9 | 10 | /** @prop --focus-color: Defines the color when the component is focused. */ 11 | --fieldset-focus-color: var(--dnn-color-primary, #3792ED); 12 | 13 | /** @prop --danger-color: Defines the danger color used for invalid data. */ 14 | --fieldset-danger-color: var(--dnn-color-danger, #900); 15 | 16 | /** @prop --control-radius: Defines the radius for the control corners. */ 17 | --fieldset-control-radius: var(--dnn-controls-radius, 3px); 18 | } 19 | 20 | .container{ 21 | border: 1px solid var(--fieldset-foreground-color, #000); 22 | border-radius: var(--fieldset-control-radius, 3px); 23 | padding: 0.75em; 24 | display: flex; 25 | justify-content: space-between; 26 | gap: 0.1em; 27 | position: relative; 28 | background-color: var(--fieldset-background-color); 29 | margin-top: 1em; 30 | line-height: 1em; 31 | .resizer{ 32 | width: 100%; 33 | } 34 | .inner-container{ 35 | position: relative; 36 | width: 100%; 37 | background-color: var(--fieldset-background-color); 38 | height: calc(100% - 1em); 39 | } 40 | label{ 41 | display: inline-flex; 42 | position: absolute; 43 | opacity: 1; 44 | transition: all 150ms ease-in-out; 45 | left: 0.5em; 46 | top: -1.5em; 47 | padding: 0 0.5em; 48 | background-color: var(--fieldset-background-color); 49 | white-space: nowrap; 50 | max-width: 100%; 51 | border-radius: var(--fieldset-control-radius); 52 | font-size: 1em; 53 | margin-top: 1em; 54 | z-index: 1; 55 | pointer-events: none; 56 | line-height: 1em; 57 | } 58 | &.focused{ 59 | border: 1px solid var(--fieldset-focus-color); 60 | box-shadow: 0 0 0 1px var(--fieldset-focus-color); 61 | &.invalid{ 62 | border: 1px solid var(--fieldset-danger-color); 63 | box-shadow: 0 0 0 1px var(--fieldset-danger-color); 64 | } 65 | input{ 66 | color: var(--fieldset-foreground-color, #000); 67 | } 68 | } 69 | &.float-label{ 70 | label{ 71 | opacity: 0.6; 72 | left: 0; 73 | top: calc(50% - 0.5em); 74 | margin-top:0; 75 | } 76 | } 77 | &.disabled{ 78 | opacity: 0.5; 79 | } 80 | &.invalid{ 81 | border-color: var(--fieldset-danger-color); 82 | } 83 | } 84 | 85 | .help-text, .error-message{ 86 | font-style: italic; 87 | opacity: 0.7; 88 | font-size: 0.8em; 89 | margin: 0.25em; 90 | } 91 | .error-message{ 92 | color: var(--fieldset-danger-color); 93 | font-style: normal; 94 | font-weight: bold; 95 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-image-cropper/CornerType.ts: -------------------------------------------------------------------------------- 1 | enum CornerType { 2 | "nw", 3 | "ne", 4 | "se", 5 | "sw", 6 | }; 7 | 8 | export default CornerType; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-image-cropper/dnn-image-cropper.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | } 4 | canvas { 5 | display: none; 6 | } 7 | .view{ 8 | visibility: hidden; 9 | opacity: 0; 10 | height: 0; 11 | overflow: hidden; 12 | transition: all 300ms ease-in-out; 13 | &.visible{ 14 | visibility: visible; 15 | opacity: 1; 16 | height: initial; 17 | overflow: visible; 18 | } 19 | .cropper{ 20 | position: relative; 21 | width: 100%; 22 | img{ 23 | width: 100%; 24 | display: block; 25 | margin: 0 auto; 26 | } 27 | .backdrop{ 28 | backdrop-filter: saturate(0.5); 29 | backdrop-filter: brightness(0.5); 30 | position: absolute; 31 | left: 0; 32 | top: 0; 33 | width: 100%; 34 | height: 100%; 35 | } 36 | .crop{ 37 | position: absolute; 38 | top: 0; 39 | left: 0; 40 | width: 100%; 41 | height: 100%; 42 | outline: 2px dashed white; 43 | box-shadow: black 0 0 0px 2px; 44 | backdrop-filter: saturate(2); 45 | backdrop-filter: brightness(2); 46 | cursor: move; 47 | >div{ 48 | width: 20px; 49 | height: 20px; 50 | background-color: white; 51 | border: 2px solid rgba(0,0,0,0.5); 52 | position: absolute; 53 | &.nw, &.ne{ 54 | top: -17px; 55 | } 56 | &.ne, &.se{ 57 | right: -17px; 58 | } 59 | &.se, &.sw{ 60 | bottom: -17px; 61 | } 62 | &.sw, &.nw{ 63 | left: -17px; 64 | } 65 | &.nw, &.se{ 66 | cursor: nwse-resize; 67 | } 68 | &.ne, &.sw{ 69 | cursor: nesw-resize; 70 | } 71 | } 72 | } 73 | } 74 | } 75 | dnn-modal{ 76 | --max-width: 512px; 77 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-image-cropper/types.ts: -------------------------------------------------------------------------------- 1 | export interface ImageCropperResx { 2 | /** The text of the capture button. */ 3 | capture?: string; 4 | 5 | /** The text of the Drag and Drop button. */ 6 | dragAndDropFile?: string; 7 | 8 | /** The word "or" shown between the controls. */ 9 | or?: string; 10 | 11 | /** The text of the button to take a picture. */ 12 | takePicture?: string; 13 | 14 | /** The text of the button to upload an image. */ 15 | uploadFile?: string; 16 | 17 | /** The text shown when an image is smaller than the minimum size supported. 18 | * {width} and {height} will be replaced by the minimum width and height. 19 | */ 20 | imageTooSmall?: string; 21 | 22 | /** The text of the Close button. */ 23 | modalCloseText?: string; 24 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-input/dnn-input.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: inline-block; 3 | 4 | /** @prop --foreground-color: Defines the foreground color. */ 5 | --foreground-color: var(--dnn-color-foreground, #000); 6 | 7 | /** @prop --background-color: Defines the background color. */ 8 | --background-color: var(--dnn-color-background, #fff); 9 | 10 | /** @prop --focus-color: Defines the color when the component is focused. */ 11 | --focus-color: var(--dnn-color-primary, #3792ED); 12 | 13 | /** @prop --danger-color: Defines the danger color used for invalid data. */ 14 | --danger-color: var(--dnn-color-danger, #900); 15 | 16 | /** @prop --control-radius: Defines the radius for the control corners. */ 17 | --control-radius: var(--dnn-controls-radius, 3px); 18 | 19 | /** @prop --input-text-align: Allows customizing the text alignment of the input text. */ 20 | --input-text-align: left; 21 | } 22 | 23 | dnn-fieldset{ 24 | width: 100%; 25 | } 26 | 27 | .inner-container{ 28 | display: flex; 29 | justify-content: space-between; 30 | position: relative; 31 | width: 100%; 32 | } 33 | input{ 34 | border: none; 35 | outline: none; 36 | background-color: transparent; 37 | color: var(--foreground); 38 | text-align: var(--input-text-align); 39 | width: 100%; 40 | } 41 | 42 | .prefix, .suffix{ 43 | font-size: 0.8em; 44 | } 45 | svg{ 46 | &.error{ 47 | fill: red; 48 | width: 1em; 49 | height: 1em; 50 | transform: scale(1.5); 51 | margin-right: 0.5em; 52 | } 53 | } 54 | button.show-password{ 55 | border: none; 56 | background-color: transparent; 57 | margin: 0; 58 | padding: 0; 59 | svg{ 60 | height: 1em; 61 | width: auto; 62 | fill: var(--foreground); 63 | transform: scale(1.5); 64 | } 65 | } 66 | 67 | dnn-fieldset{ 68 | --fieldset-foreground-color: var(--foreground-color); 69 | --fieldset-background-color: var(--background-color); 70 | --fieldset-focus-color: var(--focus-color); 71 | --fieldset-danger-color: var(--danger-color); 72 | --fieldset-control-radius: var(--control-radius); 73 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-modal/dnn-modal.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | /** 3 | * @prop --max-width: The maximum width of the module. 4 | */ 5 | display: block; 6 | .overlay{ 7 | background-color: rgba(0,0,0,0.5); 8 | position: fixed; 9 | top:0; 10 | left:0; 11 | width: 100%; 12 | height: 100%; 13 | z-index: 1002; // DNN default theme has menus on z-index 1001 14 | display: flex; 15 | justify-content: center; 16 | align-items: center; 17 | backdrop-filter: blur(2px); 18 | transition: all 300ms ease-in-out; 19 | visibility: hidden; 20 | opacity: 0; 21 | .modal{ 22 | max-width: var(--max-width, 1200px); 23 | background-color: white; 24 | padding: 30px; 25 | transform: scale(2); 26 | transition: transform 300ms ease-in-out; 27 | z-index: 2; 28 | position: relative; 29 | max-height: 80%; 30 | border-radius: var(--dnn-controls-radius, 5px); 31 | box-shadow: 10px 10px 20px 0 rgba(0,0,0,0.5); 32 | display: block; 33 | .content{ 34 | max-width: 80vw; 35 | max-height: 80vh; 36 | overflow: auto; 37 | } 38 | .se { 39 | position: absolute; 40 | height: 10px; 41 | width: 10px; 42 | bottom: -5px; 43 | right: -5px; 44 | cursor: se-resize; 45 | } 46 | .close{ 47 | position: absolute; 48 | background-color:white; 49 | border: 2px solid white; 50 | border-radius: 50%; 51 | padding: 0; 52 | margin: 0; 53 | top: -12px; 54 | right: -12px; 55 | outline: none; 56 | display: flex; 57 | justify-content: center; 58 | align-items: center; 59 | &:focus-visible, &:hover{ 60 | box-shadow: 0 0 2px 2px var(--dnn-color-primary, blue); 61 | } 62 | svg{ 63 | width: 24px; 64 | height: 24px; 65 | color: grey; 66 | } 67 | } 68 | } 69 | &.visible{ 70 | visibility: visible; 71 | opacity: 1; 72 | .modal{ 73 | transform: scale(1); 74 | box-shadow: 4px 4px 10px 0px rgba(0,0,0,0.5); 75 | display: block; 76 | } 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-modal/dnn-modal.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/web-components'; 2 | import { html } from 'lit'; 3 | import { ifDefined } from 'lit-html/directives/if-defined.js'; 4 | import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'; 5 | import { actions } from '@storybook/addon-actions'; 6 | import readme from "./readme.md?raw"; 7 | 8 | const meta: Meta = { 9 | title: 'Elements/Modal', 10 | component: 'dnn-modal', 11 | tags: ['autodocs'], 12 | parameters: { 13 | docs: { 14 | description: { 15 | component: readme, 16 | } 17 | } 18 | }, 19 | argTypes: { 20 | preventBackdropDismiss: { 21 | control: 'boolean', 22 | }, 23 | closeText: { 24 | control: 'text', 25 | }, 26 | hideCloseButton: { 27 | control: 'boolean', 28 | }, 29 | visible: { 30 | control: 'boolean', 31 | } 32 | }, 33 | } 34 | 35 | export default meta; 36 | 37 | const eventsFromNames = actions('dismissed',); 38 | 39 | const Template = (args) => 40 | html` 41 | <dnn-modal 42 | ?prevent-backdrop-dismiss=${ifDefined(args.preventBackdropDismiss)} 43 | close-text=${ifDefined(args.closeText)} 44 | ?hide-close-button=${ifDefined(args.hideCloseButton)} 45 | ?visible=${ifDefined(args.visible)}> 46 | ${unsafeHTML(args.slot)} 47 | </dnn-modal> 48 | `; 49 | 50 | type Story = StoryObj; 51 | 52 | export const Modal: Story = Template.bind({}); 53 | Modal.args = { 54 | backdropDismiss: true, 55 | closeText: 'Close modal', 56 | showCloseButton: true, 57 | visible: true, 58 | slot: `<h1>Welcome to the DNN Modal</h1> 59 | <p>This is a modal component that can be used to display content to the user.</p>` 60 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-monaco-editor/dnn-monaco-editor.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | /** 3 | * @prop --monaco-editor-width: width of the editor, default is 100% 4 | * @prop --monaco-editor-height: height of the editor, default is 50vh 5 | */ 6 | --monaco-editor-width: 100%; 7 | --monaco-editor-height: 50vh; 8 | } 9 | 10 | .editor-container { 11 | width: var(--monaco-editor-width); 12 | height: var(--monaco-editor-height); 13 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-monaco-editor/dnn-monaco-editor.stories.ts: -------------------------------------------------------------------------------- 1 | import { html } from "lit"; 2 | import { actions } from '@storybook/addon-actions'; 3 | //import { ifDefined } from 'lit-html/directives/if-defined'; 4 | //import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'; 5 | import type { Meta, StoryObj } from '@storybook/web-components'; 6 | import readme from './readme.md'; 7 | 8 | const meta: Meta = { 9 | title: 'Elements/Monaco Editor', 10 | component: 'dnn-monaco-editor', 11 | tags: ['autodocs'], 12 | parameters: { 13 | docs: { 14 | description: { 15 | component: readme, 16 | } 17 | } 18 | }, 19 | argTypes: { 20 | language: { 21 | options: [ 22 | "bat", 23 | "c", 24 | "coffeescript", 25 | "cpp", 26 | "csharp", 27 | "css", 28 | "dockerfile", 29 | "fsharp", 30 | "go", 31 | "handlebars", 32 | "html", 33 | "ini", 34 | "java", 35 | "javascript", 36 | "json", 37 | "less", 38 | "lua", 39 | "markdown", 40 | "msdax", 41 | "objective-c", 42 | "php", 43 | "plaintext", 44 | "postiats", 45 | "powershell", 46 | "pug", 47 | "python", 48 | "r", 49 | "razor", 50 | "ruby", 51 | "sb", 52 | "scss", 53 | "sol", 54 | "sql", 55 | "swift", 56 | "typescript", 57 | "vb", 58 | "xml", 59 | "yaml", 60 | ], 61 | control: { 62 | type: "select", 63 | }, 64 | }, 65 | value: { 66 | control: "text", 67 | }, 68 | }, 69 | }; 70 | 71 | export default meta; 72 | 73 | const eventsFromNames = actions("onContentChanged"); 74 | 75 | const Template = (args) => 76 | html` 77 | <dnn-monaco-editor 78 | language=${args.language} 79 | value=${args.value} 80 | @contentChanged=${eventsFromNames.onContentChanged} 81 | /> 82 | `; 83 | 84 | export const HTML = Template.bind({}); 85 | HTML.args = { 86 | language: "html", 87 | value: '<h1>Hello World</h1>\n<div class="card">\n <p>Some text</p>\n</div>\n', 88 | }; 89 | 90 | export const Typescript = Template.bind({}); 91 | Typescript.args = { 92 | language: "typescript", 93 | value: 94 | `/** Defines basic info about a person. */ 95 | interface Person { 96 | 97 | /** The person's first name. */ 98 | firstName: string; 99 | 100 | /** The person's last name. */ 101 | lastName: string; 102 | } 103 | 104 | /** Greets a person. */ 105 | const greeter = (person: Person) => 106 | { 107 | return "Hello, " + person.firstName + " " + person.lastName; 108 | } 109 | 110 | export default greeter; 111 | ` 112 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-monaco-editor/usage/HTML.md: -------------------------------------------------------------------------------- 1 | ```html 2 | <dnn-monaco-editor 3 | language="html" 4 | value="<h1>Hello World</h1> 5 | <div class="card"> 6 | <p>Some text</p> 7 | </div>" 8 | > 9 | </dnn-monaco-editor> 10 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-monaco-editor/usage/JSX-TSX.md: -------------------------------------------------------------------------------- 1 | ```tsx 2 | <dnn-monaco-editor 3 | language="html" 4 | value="<h1>Hello World</h1> 5 | <div class="card"> 6 | <p>Some text</p> 7 | </div>" 8 | > 9 | </dnn-monaco-editor> 10 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-monaco-editor/utils/code.utils.ts: -------------------------------------------------------------------------------- 1 | export const escapeCode = (code: string | undefined): string | undefined => 2 | code?.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, '''); 3 | 4 | export const unescapeCode = (code: string | undefined): string | undefined => 5 | code 6 | ?.replace(/'&/g, '&') 7 | .replace(/</g, '<') 8 | .replace(/>/g, '>') 9 | .replace(/"/g, '"') 10 | .replace(/'/g, "'"); -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-permissions-grid/dnn-permissions-grid.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | } 4 | 5 | .add-role-row{ 6 | display: flex; 7 | gap: 1em; 8 | align-items: center; 9 | flex-wrap: wrap; 10 | label{ 11 | margin-right:0.5em; 12 | } 13 | } 14 | .search-user{ 15 | display: flex; 16 | gap: 1em; 17 | margin-top: 1em; 18 | .search-control{ 19 | position: relative; 20 | dnn-collapsible{ 21 | position: absolute; 22 | left: 0; 23 | top: calc(100% - 2px); 24 | width: 100%; 25 | box-shadow: 0px 4px 4px; 26 | .dropdown{ 27 | background-color: white; 28 | border: 1px solid lightgray; 29 | display: flex; 30 | flex-direction: column; 31 | button{ 32 | background-color: transparent; 33 | border: none; 34 | border-bottom: 1px solid lightgray; 35 | padding: 0.25em; 36 | margin: 0; 37 | text-align: left; 38 | } 39 | } 40 | } 41 | } 42 | } 43 | table{ 44 | border: 1px solid lightgray; 45 | border-collapse: collapse; 46 | margin-top: 1em; 47 | thead{ 48 | text-align: center; 49 | tr{ 50 | border-bottom: 1px solid lightgray; 51 | } 52 | th{ 53 | background-color: lightgray; 54 | padding: 0.25em 0.5em; 55 | &:first-child{ 56 | border-right: 1px solid lightgray; 57 | } 58 | } 59 | } 60 | tbody{ 61 | tr{ 62 | border-bottom: 1px dotted lightgray; 63 | th{ 64 | text-align: left; 65 | border-right: 1px solid lightgray; 66 | padding: 0 0.5em; 67 | } 68 | td{ 69 | text-align: center; 70 | label{ 71 | .hidden{ 72 | display: none; 73 | } 74 | } 75 | button{ 76 | background-color: transparent; 77 | border: 0; 78 | padding: 0; 79 | margin: 0; 80 | margin-right: 1em; 81 | } 82 | } 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-permissions-grid/localization-interface.ts: -------------------------------------------------------------------------------- 1 | export interface ILocalization{ 2 | Add: string; 3 | AllRoles: string; 4 | FilterByGroup: string; 5 | GlobalRoles: string; 6 | Role: string; 7 | RolePermissions: string; 8 | SelectRole: string; 9 | User: string; 10 | UserPermissions: string; 11 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-permissions-grid/permissions-interface.ts: -------------------------------------------------------------------------------- 1 | export interface IPermissions { 2 | permissionDefinitions: IPermissionDefinition[]; 3 | rolePermissions: IRolePermission[]; 4 | userPermissions: IUserPermission[]; 5 | }; 6 | 7 | export interface IPermissionDefinition 8 | { 9 | allowAccess: boolean; 10 | fullControl: boolean; 11 | permissionCode: string; 12 | permissionId: number; 13 | permissionKey: string; 14 | permissionName: string; 15 | view: boolean; 16 | } 17 | 18 | export interface IRolePermission{ 19 | default: boolean; 20 | locked: boolean; 21 | permissions: IPermissionDefinition[]; 22 | roleId: number; 23 | roleName: string; 24 | } 25 | 26 | export interface IUserPermission{ 27 | displayName: string; 28 | permissions: IPermissionDefinition[]; 29 | userId: number; 30 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-permissions-grid/readme.md: -------------------------------------------------------------------------------- 1 | # dnn-permissions-grid 2 | 3 | 4 | 5 | <!-- Auto Generated Below --> 6 | 7 | 8 | ## Properties 9 | 10 | | Property | Attribute | Description | Type | Default | 11 | | -------------------------- | ------------- | ---------------------------------------------------------------------------------- | ---------------------------- | ----------- | 12 | | `foundUsers` | `found-users` | The list of users to show under the search users field when a search is performed. | `ISearchedUser[]` | `[]` | 13 | | `permissions` _(required)_ | `permissions` | The list of permissions. | `IPermissions` | `undefined` | 14 | | `resx` | `resx` | Optionally allows localizing the component strings. | `ILocalization \| undefined` | `undefined` | 15 | | `roleGroups` _(required)_ | `role-groups` | The list of role groups. | `IRoleGroup[]` | `undefined` | 16 | | `roles` _(required)_ | `roles` | The list of possible roles. | `IRole[]` | `undefined` | 17 | 18 | 19 | ## Events 20 | 21 | | Event | Description | Type | 22 | | ------------------------ | --------------------------------------------------------------------------------------------- | --------------------------- | 23 | | `permissionsChanged` | Fires when any permissions have changed, can be used for instance to have linked permissions. | `CustomEvent<IPermissions>` | 24 | | `userSearchQueryChanged` | Fires when searching for users to add to the permissions. Emits the search query. | `CustomEvent<string>` | 25 | 26 | 27 | ## Dependencies 28 | 29 | ### Depends on 30 | 31 | - [dnn-checkbox](../dnn-checkbox) 32 | - [dnn-button](../dnn-button) 33 | - [dnn-searchbox](../dnn-searchbox) 34 | - [dnn-collapsible](../dnn-collapsible) 35 | 36 | ### Graph 37 | ```mermaid 38 | graph TD; 39 | dnn-permissions-grid --> dnn-checkbox 40 | dnn-permissions-grid --> dnn-button 41 | dnn-permissions-grid --> dnn-searchbox 42 | dnn-permissions-grid --> dnn-collapsible 43 | dnn-button --> dnn-modal 44 | dnn-button --> dnn-button 45 | style dnn-permissions-grid fill:#f9f,stroke:#333,stroke-width:4px 46 | ``` 47 | 48 | ---------------------------------------------- 49 | 50 | *Built with [StencilJS](https://stenciljs.com/)* 51 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-permissions-grid/role-group-interface.ts: -------------------------------------------------------------------------------- 1 | export interface IRoleGroup{ 2 | description: string; 3 | id: number; 4 | name: string; 5 | rolesCount: number; 6 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-permissions-grid/role-interface.ts: -------------------------------------------------------------------------------- 1 | export interface IRole{ 2 | IsSystemRole: boolean; 3 | RoleGroupId: number; 4 | RoleId: number; 5 | RoleName: string; 6 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-permissions-grid/searched-user-interface.ts: -------------------------------------------------------------------------------- 1 | export interface ISearchedUser{ 2 | userId: number; 3 | displayName: string; 4 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-progress-bar/dnn-progress-bar.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | /** @prop --min-width: The minimum width of the progress bar. */ 3 | --min-width: 160px; 4 | 5 | /** @prop --height: The height of the progress bar. */ 6 | --height: 2rem; 7 | 8 | /** @prop --background-color: The background color of the progress bar. */ 9 | --background-color: var(--dnn-color-neutral-light, #eee); 10 | 11 | /** @prop --value-background-color: The value background color of the progress bar. */ 12 | --value-background-color: var(--dnn-color-primary, green); 13 | 14 | /** @prop --gradient-color-start: The gradient start color of the progress bar. */ 15 | --gradient-color-start: var(--dnn-color-primary, #09c); 16 | 17 | /** @prop --gradient-color-end: The gradient end color of the progress bar. */ 18 | --gradient-color-end: var(--dnn-color-primary-light, #f44); 19 | 20 | /** @prop --gradient-direction: The gradient direction of the progress bar. */ 21 | --gradient-direction: left; 22 | 23 | /** @prop --border-radius: The border radius of the progress bar. */ 24 | --border-radius: var(--dnn-controls-radius, 5px); 25 | 26 | display: inline-block; 27 | 28 | progress { 29 | height: var(--height); 30 | min-width: var(--min-width); 31 | width: 100%; 32 | } 33 | 34 | progress[value] { 35 | /* Reset the default appearance */ 36 | -webkit-appearance: none; 37 | appearance: none; 38 | } 39 | 40 | progress[value]::-webkit-progress-bar { 41 | background-color: var(--background-color); 42 | border-radius: var(--border-radius); 43 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25) inset; 44 | } 45 | 46 | progress[value]::-webkit-progress-value { 47 | border-radius: var(--border-radius); 48 | background-color: var(--value-background-color); 49 | background-size: calc(var(--height) * 1.75) var(--height), 100% 100%, 100% 100%; 50 | } 51 | 52 | progress[value].use-gradient::-webkit-progress-value { 53 | background-image: 54 | -webkit-linear-gradient(-45deg, 55 | transparent 33%, rgba(255, 255, 255, .2) 33%, 56 | rgba(255, 255, 255, .2) 66%, transparent 66%), 57 | -webkit-linear-gradient(var(--gradient-direction), var(--gradient-color-start), var(--gradient-color-end)); 58 | 59 | border-radius: var(--border-radius); 60 | background-size: calc(var(--height) * 1.75) var(--height), 100% 100%, 100% 100%; 61 | } 62 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-progress-bar/dnn-progress-bar.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/web-components'; 2 | import { html } from 'lit'; 3 | import { ifDefined } from 'lit-html/directives/if-defined.js'; 4 | import readme from "./readme.md?raw"; 5 | 6 | const meta: Meta = { 7 | title: 'Elements/Progress Bar', 8 | component: 'dnn-progress-bar', 9 | tags: ['autodocs'], 10 | parameters: { 11 | docs: { 12 | description: { 13 | component: readme, 14 | } 15 | } 16 | }, 17 | argTypes: { 18 | value: { 19 | control: 'number', 20 | }, 21 | max: { 22 | control: 'number', 23 | }, 24 | useGradient: { 25 | control: 'boolean', 26 | }, 27 | }, 28 | }; 29 | export default meta; 30 | 31 | const Template = (args) => 32 | html` 33 | <dnn-progress-bar 34 | max=${ifDefined(args.max)} 35 | value=${ifDefined(args.value)} 36 | use-gradient=${ifDefined(args.useGradient)} 37 | > 38 | </dnn-progress-bar> 39 | `; 40 | 41 | 42 | type Story = StoryObj; 43 | 44 | export const Default : Story = Template.bind({}); 45 | Default.args = { 46 | max: '100', 47 | value: '80', 48 | useGradient: false, 49 | }; 50 | 51 | export const Gradient : Story = Template.bind({}); 52 | Gradient.args = { 53 | ...Default.args, 54 | useGradient: true, 55 | }; 56 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-progress-bar/dnn-progress-bar.tsx: -------------------------------------------------------------------------------- 1 | import { Component, Prop, Host, h } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'dnn-progress-bar', 5 | styleUrl: 'dnn-progress-bar.scss', 6 | shadow: true, 7 | }) 8 | export class DnnProgressBar { 9 | 10 | /** Sets to current value for the progress bar. */ 11 | @Prop() value = 0; 12 | 13 | /** Sets the max value for the progress bar. */ 14 | @Prop() max: number = 100; 15 | 16 | /** Determines if gradient colors will be used for progress bar. */ 17 | @Prop() useGradient: boolean = false; 18 | 19 | private getProgressClass() { 20 | const classes: string[] = []; 21 | if (this.useGradient) { 22 | classes.push("use-gradient"); 23 | } 24 | return classes.join(" "); 25 | } 26 | 27 | render() { 28 | return ( 29 | <Host> 30 | <progress class={this.getProgressClass()} max={this.max} value={this.value}></progress> 31 | </Host> 32 | ); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-progress-bar/readme.md: -------------------------------------------------------------------------------- 1 | # dnn-progress-bar 2 | 3 | 4 | 5 | <!-- Auto Generated Below --> 6 | 7 | 8 | ## Usage 9 | 10 | ### HTML 11 | 12 | ```html 13 | <dnn-progress-bar 14 | max="100" 15 | value="80" 16 | use-gradient="false" 17 | > 18 | </dnn-progress-bar> 19 | ``` 20 | 21 | 22 | ### JSX-TSX 23 | 24 | ```tsx 25 | <dnn-progress-bar 26 | max="100" 27 | value="80" 28 | useGradient="false" 29 | > 30 | </dnn-progress-bar> 31 | ``` 32 | 33 | 34 | 35 | ## Properties 36 | 37 | | Property | Attribute | Description | Type | Default | 38 | | ------------- | -------------- | ------------------------------------------------------------ | --------- | ------- | 39 | | `max` | `max` | Sets the max value for the progress bar. | `number` | `100` | 40 | | `useGradient` | `use-gradient` | Determines if gradient colors will be used for progress bar. | `boolean` | `false` | 41 | | `value` | `value` | Sets to current value for the progress bar. | `number` | `0` | 42 | 43 | 44 | ## CSS Custom Properties 45 | 46 | | Name | Description | 47 | | -------------------------- | ----------------------------------------------- | 48 | | `--background-color` | The background color of the progress bar. | 49 | | `--border-radius` | The border radius of the progress bar. | 50 | | `--gradient-color-end` | The gradient end color of the progress bar. | 51 | | `--gradient-color-start` | The gradient start color of the progress bar. | 52 | | `--gradient-direction` | The gradient direction of the progress bar. | 53 | | `--height` | The height of the progress bar. | 54 | | `--min-width` | The minimum width of the progress bar. | 55 | | `--value-background-color` | The value background color of the progress bar. | 56 | 57 | 58 | ---------------------------------------------- 59 | 60 | *Built with [StencilJS](https://stenciljs.com/)* 61 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-progress-bar/usage/HTML.md: -------------------------------------------------------------------------------- 1 | ```html 2 | <dnn-progress-bar 3 | max="100" 4 | value="80" 5 | use-gradient="false" 6 | > 7 | </dnn-progress-bar> 8 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-progress-bar/usage/JSX-TSX.md: -------------------------------------------------------------------------------- 1 | ```tsx 2 | <dnn-progress-bar 3 | max="100" 4 | value="80" 5 | useGradient="false" 6 | > 7 | </dnn-progress-bar> 8 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-richtext/dnn-richtext.stories.ts: -------------------------------------------------------------------------------- 1 | import { html } from "lit"; 2 | import { actions } from '@storybook/addon-actions'; 3 | import type { Meta, StoryObj } from '@storybook/web-components'; 4 | import readme from './readme.md'; 5 | 6 | const meta: Meta = { 7 | title: 'Elements/Richtext', 8 | component: 'dnn-richtext', 9 | tags: ['autodocs'], 10 | parameters: { 11 | docs: { 12 | description: { 13 | component: readme, 14 | } 15 | } 16 | }, 17 | argTypes: { 18 | value: { 19 | control: "text", 20 | }, 21 | options: { 22 | control: "object", 23 | } 24 | }, 25 | }; 26 | 27 | export default meta; 28 | 29 | const eventsFromNames = actions("onValueChange", "onValueInput"); 30 | 31 | const Template = (args) => 32 | html` 33 | <dnn-richtext 34 | value=${args.value} 35 | .options=${args.options} 36 | @valueChange=${eventsFromNames.onValueChange} 37 | @valueInput=${eventsFromNames.onValueInput} 38 | /> 39 | `; 40 | 41 | export const Default = Template.bind({}); 42 | Default.args = { 43 | value: '<h1>Hello World</h1>\n<div class="card">\n <p>Some text</p>\n</div>\n', 44 | }; 45 | 46 | export const Basic = Template.bind({}); 47 | Basic.args = { 48 | ...Default.args, 49 | options: { 50 | buttons: "bold,italic,underline,strikethrough,eraser,ul,ol,paragraph,superscript,subscript,spellcheck,cut,copy,paste,selectall,copyformat,hr,link", 51 | }, 52 | }; 53 | 54 | export const Minimal = Template.bind({}); 55 | Minimal.args = { 56 | ...Default.args, 57 | options: { 58 | buttons: "bold,italic,underline,", 59 | }, 60 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-searchbox/dnn-searchbox.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | position: relative; 3 | display: flex; 4 | justify-content: space-between; 5 | --background-color: transparent; 6 | --color: #333; 7 | --border-size: 1px; 8 | --border-color: grey; 9 | --border-active-color: black; 10 | --border-radius: var(--dnn-controls-radius, 5px); 11 | --padding: var(--dnn-controls-padding, 5px); 12 | --focus-color: var(--dnn-color-primary, blue); 13 | input { 14 | width:100%; 15 | border: var(--border-size) solid var(--border-color); 16 | outline: none; 17 | border-radius: var(--border-radius); 18 | padding: var(--padding); 19 | padding-right: 32px; 20 | transition: all 300ms ease-in-out; 21 | &:focus-visible, &:hover{ 22 | outline: none; 23 | box-shadow: 0 0 2px 2px var(--focus-color); 24 | } 25 | } 26 | svg{ 27 | position: absolute; 28 | top:0; 29 | right:0; 30 | height: 100%; 31 | transform: scale(0.7); 32 | fill: var(--color); 33 | outline: var(--color); 34 | color: var(--color); 35 | transition: all 300ms ease-in-out; 36 | } 37 | button{ 38 | background: transparent; 39 | border: 0; 40 | margin: 0; 41 | padding: 0; 42 | &:focus-visible, &:hover{ 43 | svg{ 44 | fill: var(--focus-color); 45 | outline: var(--focus-color); 46 | color: var(--focus-color); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-searchbox/dnn-searchbox.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/web-components'; 2 | import { html } from 'lit'; 3 | import { actions } from '@storybook/addon-actions'; 4 | import readme from "./readme.md?raw"; 5 | 6 | const meta: Meta = { 7 | title: "Elements/Searchbox", 8 | component: "dnn-searchbox", 9 | tags: ['autodocs'], 10 | parameters: { 11 | docs: { 12 | description: { 13 | component: readme, 14 | } 15 | } 16 | } 17 | } 18 | export default meta; 19 | 20 | const eventsFromNames = actions('queryChanged',); 21 | 22 | const Template = (args : { 23 | debounced: boolean, 24 | placeholder: string, 25 | query: string, 26 | }) => 27 | html` 28 | <dnn-searchbox 29 | ?debounced=${args.debounced} 30 | placeholder=${args.placeholder} 31 | query=${args.query} 32 | /> 33 | `; 34 | 35 | type Story = StoryObj; 36 | 37 | export const Searchbox: Story = Template.bind({}); 38 | Searchbox.args = { 39 | debounced: true, 40 | placeholder: "Search", 41 | query: "", 42 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-searchbox/dnn-searchbox.tsx: -------------------------------------------------------------------------------- 1 | import { Component, Host, h, Event, EventEmitter, Watch, Prop, State } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'dnn-searchbox', 5 | styleUrl: 'dnn-searchbox.scss', 6 | shadow: true 7 | }) 8 | export class DnnSearchbox { 9 | 10 | /** 11 | * Sets the field placeholder text. 12 | */ 13 | @Prop() placeholder?: string = ""; 14 | 15 | /** 16 | * How many milliseconds to wait before firing the queryChanged event. 17 | */ 18 | @Prop() debounceTime: number = 500; 19 | 20 | /** Sets the query */ 21 | @Prop({mutable: true}) query: string = ""; 22 | 23 | /** 24 | * Fires up each time the search query changes. 25 | * The data passed is the new query. 26 | */ 27 | @Event() queryChanged!: EventEmitter<string>; 28 | 29 | @Watch('query') 30 | handleQueryChanged(){ 31 | clearTimeout(this.debounceTimer); 32 | this.debounceTimer = setTimeout(() => { 33 | this.queryChanged.emit(this.query); 34 | }, this.debounceTime); 35 | } 36 | 37 | @State() focused: any; 38 | 39 | private inputField!: HTMLInputElement; 40 | 41 | private debounceTimer: any = null; 42 | 43 | render() { 44 | return ( 45 | <Host 46 | tabIndex={this.focused ? -1 : 0} 47 | onFocus={() => this.inputField.focus()} 48 | onBlur={() => this.inputField.blur()} 49 | > 50 | <input 51 | ref={el => this.inputField = el!} 52 | type="text" 53 | value={this.query} 54 | placeholder={this.placeholder} 55 | onInput={e => this.query = (e.target as HTMLInputElement).value} 56 | onFocus={() => this.focused = true} 57 | onBlur={() => this.focused = false} 58 | /> 59 | {this.query !== "" ? 60 | <button class="svg clear" 61 | onClick={() => this.query = ""} 62 | > 63 | <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z"/></svg> 64 | </button> 65 | : 66 | <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg> 67 | } 68 | </Host> 69 | ); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-searchbox/readme.md: -------------------------------------------------------------------------------- 1 | # dnn-searchbox 2 | 3 | 4 | 5 | <!-- Auto Generated Below --> 6 | 7 | 8 | ## Properties 9 | 10 | | Property | Attribute | Description | Type | Default | 11 | | -------------- | --------------- | ------------------------------------------------------------------- | --------------------- | ------- | 12 | | `debounceTime` | `debounce-time` | How many milliseconds to wait before firing the queryChanged event. | `number` | `500` | 13 | | `placeholder` | `placeholder` | Sets the field placeholder text. | `string \| undefined` | `""` | 14 | | `query` | `query` | Sets the query | `string` | `""` | 15 | 16 | 17 | ## Events 18 | 19 | | Event | Description | Type | 20 | | -------------- | ------------------------------------------------------------------------------ | --------------------- | 21 | | `queryChanged` | Fires up each time the search query changes. The data passed is the new query. | `CustomEvent<string>` | 22 | 23 | 24 | ## Dependencies 25 | 26 | ### Used by 27 | 28 | - [dnn-permissions-grid](../dnn-permissions-grid) 29 | 30 | ### Graph 31 | ```mermaid 32 | graph TD; 33 | dnn-permissions-grid --> dnn-searchbox 34 | style dnn-searchbox fill:#f9f,stroke:#333,stroke-width:4px 35 | ``` 36 | 37 | ---------------------------------------------- 38 | 39 | *Built with [StencilJS](https://stenciljs.com/)* 40 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-select/dnn-select.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: inline-block; 3 | 4 | /** @prop --foreground-color: Defines the foreground color. */ 5 | --foreground-color: var(--dnn-color-foreground, #000); 6 | 7 | /** @prop --background-color: Defines the background color. */ 8 | --background-color: var(--dnn-color-background, #fff); 9 | 10 | /** @prop --focus-color: Defines the color when the component is focused. */ 11 | --focus-color: var(--dnn-color-primary, #3792ED); 12 | 13 | /** @prop --danger-color: Defines the danger color used for invalid data. */ 14 | --danger-color: var(--dnn-color-danger, #900); 15 | 16 | /** @prop --control-radius: Defines the radius for the control corners. */ 17 | --control-radius: var(--dnn-controls-radius, 3px); 18 | 19 | /** @prop --input-text-align: Allows customizing the text alignment of the input text. */ 20 | --input-text-align: left; 21 | } 22 | 23 | dnn-fieldset{ 24 | width: 100%; 25 | } 26 | 27 | .inner-container{ 28 | display: flex; 29 | justify-content: space-between; 30 | position: relative; 31 | width: 100%; 32 | background-color: var(--background-color); 33 | } 34 | 35 | select{ 36 | border: none; 37 | outline: none; 38 | background-color: var(--background-color); 39 | color: var(--foreground-color); 40 | text-align: var(--input-text-align); 41 | width: 100%; 42 | cursor: pointer; 43 | } 44 | 45 | .prefix, .suffix{ 46 | font-size: 0.8em; 47 | } 48 | svg{ 49 | &.error{ 50 | fill: red; 51 | width: 1em; 52 | height: 1em; 53 | transform: scale(1.5); 54 | } 55 | } 56 | 57 | dnn-fieldset{ 58 | --fieldset-foreground-color: var(--foreground-color); 59 | --fieldset-background-color: var(--background-color); 60 | --fieldset-focus-color: var(--focus-color); 61 | --fieldset-danger-color: var(--danger-color); 62 | --fieldset-control-radius: var(--control-radius); 63 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-select/dnn-select.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/web-components'; 2 | import { html, nothing, TemplateResult } from 'lit'; 3 | import { ifDefined } from 'lit-html/directives/if-defined.js'; 4 | import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'; 5 | import { actions } from '@storybook/addon-actions'; 6 | import readme from "./readme.md?raw"; 7 | 8 | const meta: Meta = { 9 | title: 'Elements/Select', 10 | component: 'dnn-select', 11 | tags: ['autodocs'], 12 | parameters: { 13 | docs: { 14 | description: { 15 | component: readme, 16 | } 17 | } 18 | }, 19 | argTypes: { 20 | "disable-validity-reporting": { 21 | control: 'boolean', 22 | }, 23 | disabled: { 24 | control: 'boolean', 25 | }, 26 | "help-text": { 27 | control: 'text', 28 | }, 29 | label: { 30 | control: 'text', 31 | }, 32 | name: { 33 | control: 'text', 34 | }, 35 | required: { 36 | control: 'boolean', 37 | }, 38 | value: { 39 | control: 'text', 40 | }, 41 | }, 42 | }; 43 | export default meta; 44 | 45 | const eventsFromNames = actions("valueChange"); 46 | 47 | const Template = (args) => 48 | html` 49 | <dnn-select 50 | ?disable-validity-reporting=${args["disable-validity-reporting"]} 51 | ?disabled=${args.disabled} 52 | help-text=${ifDefined(args["help-text"])} 53 | label=${ifDefined(args.label)} 54 | name=${ifDefined(args.name)} 55 | ?required=${ifDefined(args.required)} 56 | value=${ifDefined(args.value)} 57 | @valueChange=${e => eventsFromNames.valueChange(e)} 58 | > 59 | <option value="">-- Select an option --</option> 60 | <option value="1">Option 1</option> 61 | <option value="2">Option 2</option> 62 | <option value="3">Option 3</option> 63 | </dnn-select> 64 | `; 65 | 66 | 67 | type Story = StoryObj; 68 | 69 | export const Dropdown : Story = Template.bind({}); 70 | Dropdown.args = { 71 | label: "Option", 72 | "help-text": "This is a help text", 73 | disabled: false, 74 | "disable-validity-reporting": false, 75 | readonly: false, 76 | required: false, 77 | }; 78 | 79 | export const Required : Story = Template.bind({}); 80 | Required.args = { 81 | ...Dropdown.args, 82 | required: true, 83 | } 84 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-sort-icon/dnn-sort-icon.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | /** 3 | * @prop --color: Normal Color of the inactive sort icon. 4 | * @prop --color-sorted: Color of the sorted sort icon. 5 | * @prop --color-hover: Color of the icons when hovered. 6 | */ 7 | --color: #888; 8 | --color-sorted: var(--dnn-color-primary, rgb(2,139,255)); 9 | --color-hover: var(--dnn-color-primary-light, #36a1ff); 10 | 11 | display: inline-block; 12 | } 13 | 14 | button { 15 | cursor: pointer; 16 | outline: none; 17 | border: none; 18 | margin: 0; 19 | padding: 0; 20 | background-color: transparent; 21 | outline: none; 22 | display: inline-block; 23 | line-height: 1em; 24 | position: relative; 25 | top: 0.25em; 26 | svg{ 27 | height: 1.5em; 28 | width: auto; 29 | fill: var(--color); 30 | } 31 | &.active{ 32 | svg{ 33 | fill: var(--color-sorted); 34 | } 35 | } 36 | &:hover, &:focus-visible{ 37 | svg{ 38 | fill: var(--color-hover); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-sort-icon/dnn-sort-icon.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/web-components'; 2 | import { html } from "lit"; 3 | import { ifDefined } from 'lit-html/directives/if-defined.js'; 4 | import { actions } from '@storybook/addon-actions'; 5 | import readme from "./readme.md?raw"; 6 | 7 | const meta: Meta = { 8 | title: "Elements/Sort Icon", 9 | component: 'dnn-sort-icon', 10 | tags: ['autodocs'], 11 | parameters: { 12 | docs: { 13 | description: { 14 | component: readme, 15 | } 16 | } 17 | }, 18 | argTypes: { 19 | sortDirection: { 20 | options: ['asc', 'desc', 'none'], 21 | control: { 22 | type: 'radio', 23 | }, 24 | defaultValue: "none", 25 | }, 26 | color: { 27 | control: { 28 | type: 'color' 29 | } 30 | }, 31 | colorHover: { 32 | control: { 33 | type: 'color' 34 | } 35 | }, 36 | colorSorted: { 37 | control: { 38 | type: 'color' 39 | } 40 | }, 41 | }, 42 | } 43 | export default meta; 44 | 45 | const eventsFromNames = actions('sortChanged',); 46 | 47 | const Template = (args: { 48 | sortDirection: "asc" | "desc" | "none", 49 | color: string; 50 | }, context) => 51 | { 52 | return html` 53 | <dnn-sort-icon 54 | .sortDirection=${ifDefined(args.sortDirection)} 55 | /> 56 | `; 57 | } 58 | 59 | type Story = StoryObj; 60 | 61 | export const SortIcon: Story = Template.bind({}); 62 | SortIcon.args = { 63 | sortDirection: "none", 64 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-sort-icon/dnn-sort-icon.tsx: -------------------------------------------------------------------------------- 1 | import { Component, Host, h, Prop, Event, EventEmitter, State } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'dnn-sort-icon', 5 | styleUrl: 'dnn-sort-icon.scss', 6 | shadow: true 7 | }) 8 | export class DnnSortIcon { 9 | /** Defines the current sort direction */ 10 | @Prop({mutable: true}) sortDirection: "asc" | "desc" | "none" = "none"; 11 | 12 | /** Emitted when the sort is changed. */ 13 | @Event() sortChanged!: EventEmitter<"asc"|"desc"|"none">; 14 | 15 | @State() focused = false; 16 | 17 | private button!: HTMLButtonElement; 18 | 19 | private changeSort(): void { 20 | switch (this.sortDirection) { 21 | case "asc": 22 | this.sortDirection = "desc"; 23 | break; 24 | case "desc": 25 | this.sortDirection = "asc"; 26 | break; 27 | case "none": 28 | this.sortDirection = "asc"; 29 | break; 30 | default: 31 | break; 32 | } 33 | 34 | this.sortChanged.emit(this.sortDirection); 35 | } 36 | 37 | render() { 38 | return ( 39 | <Host 40 | tabIndex={this.focused ? -1 : 0} 41 | onFocus={() => this.button.focus()} 42 | onBlur={() => this.button.blur()} 43 | > 44 | <button 45 | ref={el => this.button = el!} 46 | class={{"active": this.sortDirection != "none"}} 47 | onClick={() => this.changeSort()} 48 | onFocus={() => this.focused = true} 49 | onBlur={() => this.focused = false} 50 | > 51 | {this.sortDirection == "none" && 52 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 16"><path d="M 0 7 H 12 L 6 0 Z M 0 9 H 12 L 6 16 Z"></path></svg> 53 | } 54 | {this.sortDirection == "asc" && 55 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 16"><path d="M 0 7 H 12 L 6 0 Z"></path></svg> 56 | } 57 | {this.sortDirection == "desc" && 58 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 16"><path d="M 0 9 H 12 L 6 16 Z"></path></svg> 59 | } 60 | </button> 61 | </Host> 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-sort-icon/readme.md: -------------------------------------------------------------------------------- 1 | # dnn-sort-icon 2 | 3 | 4 | 5 | <!-- Auto Generated Below --> 6 | 7 | 8 | ## Usage 9 | 10 | ### HTML 11 | 12 | ```html 13 | <dnn-sort-icon 14 | sort-direction="asc"> 15 | </dnn-sort-icon> 16 | ``` 17 | 18 | 19 | ### JSX-TSX 20 | 21 | ```tsx 22 | <dnn-sort-icon 23 | sortDirection="asc"> 24 | </dnn-sort-icon> 25 | ``` 26 | 27 | 28 | 29 | ## Properties 30 | 31 | | Property | Attribute | Description | Type | Default | 32 | | --------------- | ---------------- | ---------------------------------- | --------------------------- | -------- | 33 | | `sortDirection` | `sort-direction` | Defines the current sort direction | `"asc" \| "desc" \| "none"` | `"none"` | 34 | 35 | 36 | ## Events 37 | 38 | | Event | Description | Type | 39 | | ------------- | --------------------------------- | ---------------------------------------- | 40 | | `sortChanged` | Emitted when the sort is changed. | `CustomEvent<"asc" \| "desc" \| "none">` | 41 | 42 | 43 | ## CSS Custom Properties 44 | 45 | | Name | Description | 46 | | ---------------- | --------------------------------------- | 47 | | `--color` | Normal Color of the inactive sort icon. | 48 | | `--color-hover` | Color of the icons when hovered. | 49 | | `--color-sorted` | Color of the sorted sort icon. | 50 | 51 | 52 | ---------------------------------------------- 53 | 54 | *Built with [StencilJS](https://stenciljs.com/)* 55 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-sort-icon/usage/HTML.md: -------------------------------------------------------------------------------- 1 | ```html 2 | <dnn-sort-icon 3 | sort-direction="asc"> 4 | </dnn-sort-icon> 5 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-sort-icon/usage/JSX-TSX.md: -------------------------------------------------------------------------------- 1 | ```tsx 2 | <dnn-sort-icon 3 | sortDirection="asc"> 4 | </dnn-sort-icon> 5 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-tab/dnn-tab.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DNNCommunity/dnn-elements/e1699edc1562e75a2ab269e8fee6d2802ba35d90/packages/stencil-library/src/components/dnn-tab/dnn-tab.scss -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-tab/dnn-tab.tsx: -------------------------------------------------------------------------------- 1 | import { Component, Host, h, Prop, State, Method } from "@stencil/core"; 2 | 3 | /** Represents a single tab and must be used inside a dnn-tabs element. */ 4 | @Component({ 5 | tag: 'dnn-tab', 6 | styleUrl: 'dnn-tab.scss', 7 | shadow: true, 8 | }) 9 | export class DnnTab { 10 | /** Defines the tab title. */ 11 | @Prop() tabTitle!: string; 12 | 13 | @State() visible: boolean = false; 14 | 15 | /** Shows the tab. */ 16 | @Method() 17 | async show(){ 18 | this.visible = true; 19 | } 20 | 21 | /** Hides the modal */ 22 | @Method() 23 | async hide(){ 24 | this.visible = false; 25 | } 26 | 27 | render() { 28 | return ( 29 | <Host> 30 | {this.visible && 31 | <slot></slot> 32 | } 33 | </Host> 34 | ); 35 | } 36 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-tab/readme.md: -------------------------------------------------------------------------------- 1 | # dnn-tab 2 | 3 | `dnn-tab` should only be used as part of `dnn-tabs` in order to define the title and content of each of the tabs. 4 | 5 | <!-- Auto Generated Below --> 6 | 7 | 8 | ## Overview 9 | 10 | Represents a single tab and must be used inside a dnn-tabs element. 11 | 12 | ## Usage 13 | 14 | ### HTML 15 | 16 | ```html 17 | <dnn-tabs> 18 | <dnn-tab tab-title="First Tab"> 19 | <p>Content of the first tab.</p> 20 | </dnn-tab> 21 | <dnn-tab tab-title="Second Tab"> 22 | <p>This is the second tab</p> 23 | </dnn-tab> 24 | </dnn-tabs> 25 | ``` 26 | 27 | 28 | ### JSX-TSX 29 | 30 | ```tsx 31 | <dnn-tabs> 32 | <dnn-tab tabTitle="First Tab"> 33 | <p>Content of the first tab.</p> 34 | </dnn-tab> 35 | <dnn-tab tabTitle="Second Tab"> 36 | <p>This is the second tab</p> 37 | </dnn-tab> 38 | </dnn-tabs> 39 | ``` 40 | 41 | 42 | 43 | ## Properties 44 | 45 | | Property | Attribute | Description | Type | Default | 46 | | ----------------------- | ----------- | ---------------------- | -------- | ----------- | 47 | | `tabTitle` _(required)_ | `tab-title` | Defines the tab title. | `string` | `undefined` | 48 | 49 | 50 | ## Methods 51 | 52 | ### `hide() => Promise<void>` 53 | 54 | Hides the modal 55 | 56 | #### Returns 57 | 58 | Type: `Promise<void>` 59 | 60 | 61 | 62 | ### `show() => Promise<void>` 63 | 64 | Shows the tab. 65 | 66 | #### Returns 67 | 68 | Type: `Promise<void>` 69 | 70 | 71 | 72 | 73 | ## Dependencies 74 | 75 | ### Used by 76 | 77 | - [dnn-color-input](../dnn-color-input) 78 | 79 | ### Graph 80 | ```mermaid 81 | graph TD; 82 | dnn-color-input --> dnn-tab 83 | style dnn-tab fill:#f9f,stroke:#333,stroke-width:4px 84 | ``` 85 | 86 | ---------------------------------------------- 87 | 88 | *Built with [StencilJS](https://stenciljs.com/)* 89 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-tab/usage/HTML.md: -------------------------------------------------------------------------------- 1 | ```html 2 | <dnn-tabs> 3 | <dnn-tab tab-title="First Tab"> 4 | <p>Content of the first tab.</p> 5 | </dnn-tab> 6 | <dnn-tab tab-title="Second Tab"> 7 | <p>This is the second tab</p> 8 | </dnn-tab> 9 | </dnn-tabs> 10 | ``` 11 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-tab/usage/JSX-TSX.md: -------------------------------------------------------------------------------- 1 | ```tsx 2 | <dnn-tabs> 3 | <dnn-tab tabTitle="First Tab"> 4 | <p>Content of the first tab.</p> 5 | </dnn-tab> 6 | <dnn-tab tabTitle="Second Tab"> 7 | <p>This is the second tab</p> 8 | </dnn-tab> 9 | </dnn-tabs> 10 | ``` 11 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-tabs/dnn-tabs.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | /** 3 | * @prop --color-background: The color of the inactive tabs. 4 | * @prop --color-text: The color of the text for inactive tabs. 5 | * @prop --color-visible: The color of the active tab. 6 | * @prop --color-visible-text: The color of the text for the active tab. 7 | * @prop --color-focus: outline color when hovering or pre-selecting a tab. 8 | */ 9 | display: block; 10 | --color-background: var(--dnn-color-secondary-dark, lightgray); 11 | --color-text: var(--dnn-color-secondary-contrast, #333); 12 | --color-visible: var(--dnn-color-primary, #3792ED); 13 | --color-visible-text: var(--dnn-color-primary-contrast, #FFF); 14 | --color-focus: var(--dnn-color-primary, #3792ed); 15 | } 16 | 17 | .tabTitles{ 18 | display: flex; 19 | background-color: var(--color-background); 20 | button { 21 | cursor: pointer; 22 | padding: 0.5rem 1rem; 23 | border: 0; 24 | margin: 0; 25 | background-color: transparent; 26 | color: var(--color-text); 27 | 28 | &.visible { 29 | background-color: var(--color-visible); 30 | color: var(--color-visible-text); 31 | } 32 | 33 | &:focus-visible, &:hover { 34 | outline: none; 35 | box-shadow: 0 0 2px 2px var(--color-focus); 36 | } 37 | } 38 | } 39 | 40 | .currentTab{ 41 | border: 1px solid var(--color-background); 42 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-tabs/dnn-tabs.tsx: -------------------------------------------------------------------------------- 1 | import { Component, Host, h, State } from "@stencil/core"; 2 | 3 | @Component({ 4 | tag: 'dnn-tabs', 5 | styleUrl: 'dnn-tabs.scss', 6 | shadow: true, 7 | }) 8 | export class DnnTabs { 9 | private component!: HTMLElement; 10 | 11 | @State() tabTitles: string[] = []; 12 | @State() selectedTabTitle: string = ""; 13 | 14 | componentDidLoad(){ 15 | requestAnimationFrame(() => { 16 | this.updateTitles(); 17 | this.showFirstTab(); 18 | }); 19 | } 20 | 21 | private getTabs() { 22 | return this.component.shadowRoot!.querySelector("slot")!.assignedElements() as HTMLDnnTabElement[]; 23 | } 24 | 25 | private updateTitles(){ 26 | const tabs = this.getTabs(); 27 | tabs.forEach(tab => this.tabTitles = [...this.tabTitles, tab.tabTitle]); 28 | } 29 | 30 | private showFirstTab(){ 31 | const tab = this.getTabs()[0]; 32 | tab.show(); 33 | this.selectedTabTitle = tab.tabTitle; 34 | } 35 | 36 | private showTab(tabTitle: string) { 37 | const tabs = this.getTabs(); 38 | tabs.forEach(tab => { 39 | if (tab.tabTitle == tabTitle){ 40 | tab.show(); 41 | return; 42 | } 43 | 44 | tab.hide(); 45 | }); 46 | this.selectedTabTitle = tabTitle; 47 | } 48 | 49 | render() { 50 | return ( 51 | <Host ref={el => this.component = el!}> 52 | <div class="tabTitles"> 53 | {this.tabTitles.map(tabTitle => 54 | <button 55 | class={this.selectedTabTitle == tabTitle ? "visible": ""} 56 | onClick={() => this.showTab(tabTitle)} 57 | > 58 | {tabTitle} 59 | </button> 60 | )} 61 | </div> 62 | <div class="currentTab"> 63 | <slot></slot> 64 | </div> 65 | </Host> 66 | ); 67 | } 68 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-tabs/readme.md: -------------------------------------------------------------------------------- 1 | # dnn-tabs 2 | 3 | `dnn-tabs` is a container for `dnn-tab` and should only contain `dnn-tab` elements for its content. 4 | 5 | <!-- Auto Generated Below --> 6 | 7 | 8 | ## Usage 9 | 10 | ### HTML 11 | 12 | ```html 13 | <dnn-tabs> 14 | <dnn-tab tab-title="First Tab"> 15 | <p>Content of the first tab.</p> 16 | </dnn-tab> 17 | <dnn-tab tab-title="Second Tab"> 18 | <p>This is the second tab</p> 19 | </dnn-tab> 20 | </dnn-tabs> 21 | ``` 22 | 23 | 24 | ### JSX-TSX 25 | 26 | ```tsx 27 | <dnn-tabs> 28 | <dnn-tab tabTitle="First Tab"> 29 | <p>Content of the first tab.</p> 30 | </dnn-tab> 31 | <dnn-tab tabTitle="Second Tab"> 32 | <p>This is the second tab</p> 33 | </dnn-tab> 34 | </dnn-tabs> 35 | ``` 36 | 37 | 38 | 39 | ## CSS Custom Properties 40 | 41 | | Name | Description | 42 | | ---------------------- | --------------------------------------------------- | 43 | | `--color-background` | The color of the inactive tabs. | 44 | | `--color-focus` | outline color when hovering or pre-selecting a tab. | 45 | | `--color-text` | The color of the text for inactive tabs. | 46 | | `--color-visible` | The color of the active tab. | 47 | | `--color-visible-text` | The color of the text for the active tab. | 48 | 49 | 50 | ## Dependencies 51 | 52 | ### Used by 53 | 54 | - [dnn-color-input](../dnn-color-input) 55 | 56 | ### Graph 57 | ```mermaid 58 | graph TD; 59 | dnn-color-input --> dnn-tabs 60 | style dnn-tabs fill:#f9f,stroke:#333,stroke-width:4px 61 | ``` 62 | 63 | ---------------------------------------------- 64 | 65 | *Built with [StencilJS](https://stenciljs.com/)* 66 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-tabs/usage/HTML.md: -------------------------------------------------------------------------------- 1 | ```html 2 | <dnn-tabs> 3 | <dnn-tab tab-title="First Tab"> 4 | <p>Content of the first tab.</p> 5 | </dnn-tab> 6 | <dnn-tab tab-title="Second Tab"> 7 | <p>This is the second tab</p> 8 | </dnn-tab> 9 | </dnn-tabs> 10 | ``` 11 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-tabs/usage/JSX-TSX.md: -------------------------------------------------------------------------------- 1 | ```tsx 2 | <dnn-tabs> 3 | <dnn-tab tabTitle="First Tab"> 4 | <p>Content of the first tab.</p> 5 | </dnn-tab> 6 | <dnn-tab tabTitle="Second Tab"> 7 | <p>This is the second tab</p> 8 | </dnn-tab> 9 | </dnn-tabs> 10 | ``` 11 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-textarea/dnn-textarea.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: inline-block; 3 | 4 | /** @prop --foreground-color: Defines the foreground color. */ 5 | --foreground-color: var(--dnn-color-foreground, #000); 6 | 7 | /** @prop --background-color: Defines the background color. */ 8 | --background-color: var(--dnn-color-background, #fff); 9 | 10 | /** @prop --focus-color: Defines the color when the component is focused. */ 11 | --focus-color: var(--dnn-color-primary, #3792ED); 12 | 13 | /** @prop --danger-color: Defines the danger color used for invalid data. */ 14 | --danger-color: var(--dnn-color-danger, #900); 15 | 16 | /** @prop --control-radius: Defines the radius for the control corners. */ 17 | --control-radius: var(--dnn-controls-radius, 3px); 18 | } 19 | 20 | dnn-fieldset{ 21 | width: 100%; 22 | } 23 | 24 | textarea{ 25 | border: none; 26 | outline: none; 27 | background-color: transparent; 28 | color: var(--foreground-color); 29 | width: calc(100% - 1em); 30 | height: calc(100% - 1em); 31 | line-height: 1.5em; 32 | resize: none; 33 | } 34 | 35 | dnn-fieldset{ 36 | --fieldset-foreground-color: var(--foreground-color); 37 | --fieldset-background-color: var(--background-color); 38 | --fieldset-focus-color: var(--focus-color); 39 | --fieldset-danger-color: var(--danger-color); 40 | --fieldset-control-radius: var(--control-radius); 41 | } 42 | 43 | svg{ 44 | &.error{ 45 | fill: red; 46 | width: 1em; 47 | height: 1em; 48 | transform: scale(1.5); 49 | position: absolute; 50 | right: 0.5rem; 51 | top: 0.5rem; 52 | } 53 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-textarea/dnn-textarea.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/web-components'; 2 | import { html, nothing, TemplateResult } from 'lit'; 3 | import { ifDefined } from 'lit-html/directives/if-defined.js'; 4 | import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'; 5 | import { actions } from '@storybook/addon-actions'; 6 | import readme from "./readme.md?raw"; 7 | 8 | const meta: Meta = { 9 | title: 'Elements/Textarea', 10 | component: 'dnn-textarea', 11 | tags: ['autodocs'], 12 | parameters: { 13 | docs: { 14 | description: { 15 | component: readme, 16 | } 17 | } 18 | }, 19 | argTypes: { 20 | autocomplete: { 21 | type: 'string', 22 | }, 23 | disabled: { 24 | control: 'boolean', 25 | }, 26 | "help-text": { 27 | control: 'text', 28 | }, 29 | label: { 30 | control: 'text', 31 | }, 32 | minlength: { 33 | control: 'number', 34 | }, 35 | maxlength: { 36 | control: 'number', 37 | }, 38 | name: { 39 | control: 'text', 40 | }, 41 | readonly: { 42 | control: 'boolean', 43 | }, 44 | required: { 45 | control: 'boolean', 46 | }, 47 | value: { 48 | control: 'text', 49 | }, 50 | }, 51 | }; 52 | export default meta; 53 | 54 | const eventsFromNames = actions("valueChange", "valueInput"); 55 | 56 | const Template = (args) => 57 | html` 58 | <dnn-textarea 59 | autocomplete=${args.autocomplete=="off" ? nothing : args.autocomplete} 60 | ?disabled=${args.disabled} 61 | help-text=${ifDefined(args["help-text"])} 62 | label=${ifDefined(args.label)} 63 | minlength=${ifDefined(args.minlength)} 64 | maxlength=${ifDefined(args.maxlength)} 65 | name=${ifDefined(args.name)} 66 | ?readonly=${ifDefined(args.readonly)} 67 | ?required=${ifDefined(args.required)} 68 | value=${ifDefined(args.value)} 69 | @valueChange=${e => eventsFromNames.valueChange(e)} 70 | @valueInput=${e => eventsFromNames.valueInput(e)} 71 | > 72 | </dnn-input> 73 | `; 74 | 75 | 76 | type Story = StoryObj; 77 | 78 | export const Text : Story = Template.bind({}); 79 | Text.args = { 80 | autocomplete: "off", 81 | disabled: false, 82 | readonly: false, 83 | required: false, 84 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-toggle/dnn-toggle.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | /** 3 | * @prop --background: Background of the toggle. 4 | * @prop --background-checked: Background of the toggle when checked. 5 | * @prop --handle-background: Background of the handle. 6 | * @prop --handle-background-checked: Background of the handle when checked. 7 | * @prop --border-radius: The radius of the background borders. 8 | * @prop --handle-border-radius: The radius of the handle. 9 | */ 10 | 11 | display: inline-block; 12 | outline: none; 13 | cursor: pointer; 14 | } 15 | 16 | button { 17 | height: 1.5em; 18 | width: 2.5em; 19 | outline: none; 20 | background-color: var(--background, #888); 21 | border: 0; 22 | border-radius: var(--border-radius, var(--dnn-controls-radius, 0.75em)); 23 | padding: 0.1em; 24 | position: relative; 25 | margin: 0; 26 | transition: background-color 300ms ease-in-out; 27 | position: relative; 28 | cursor: pointer; 29 | &:hover, &:focus-visible{ 30 | box-shadow: 0 0 2px 2px var(--dnn-color-primary); 31 | } 32 | &.checked{ 33 | background-color: var(--background-checked, var(--dnn-color-primary, blue)); 34 | .handle{ 35 | left: calc(1em + 4px); 36 | } 37 | } 38 | &:disabled{ 39 | opacity: 0.5; 40 | cursor: not-allowed; 41 | box-shadow: none; 42 | } 43 | .handle{ 44 | transition: all 300ms ease-in-out; 45 | background-color:white; 46 | width: 1em; 47 | height: 1em; 48 | border-radius: var(--handle-border-radius, var(--dnn-controls-radius, 50%)); 49 | position: absolute; 50 | top: calc(50% - 0.5em); 51 | left: 2px; 52 | } 53 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-toggle/dnn-toggle.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/web-components'; 2 | import { html } from 'lit'; 3 | import { ifDefined } from 'lit-html/directives/if-defined.js'; 4 | import { actions } from '@storybook/addon-actions'; 5 | import readme from "./readme.md?raw"; 6 | 7 | 8 | const meta: Meta = { 9 | title: 'Elements/Toggle', 10 | component: 'dnn-toggle', 11 | tags: ['autodocs'], 12 | parameters: { 13 | docs: { 14 | description: { 15 | component: readme, 16 | } 17 | } 18 | }, 19 | argTypes: { 20 | checked: { 21 | control: 'boolean', 22 | }, 23 | disabled: { 24 | control: 'boolean', 25 | }, 26 | background: { 27 | control: 'color' 28 | }, 29 | backgroundChecked: { 30 | control: 'color' 31 | }, 32 | handleBackground: { 33 | control: 'color' 34 | }, 35 | handleBackgroundChecked: { 36 | control: 'color' 37 | }, 38 | borderRadius: { 39 | control: 'text' 40 | }, 41 | handleBorderRadius: { 42 | control: 'text' 43 | }, 44 | }, 45 | } 46 | export default meta; 47 | 48 | const eventsFromNames = actions('checkChanged',); 49 | 50 | const Template = (args: { 51 | checked: boolean; 52 | disabled: boolean; 53 | }, context) => 54 | html` 55 | <dnn-toggle 56 | ?checked=${ifDefined(args.checked)} 57 | ?disabled=${ifDefined(args.disabled)}> 58 | </dnn-toggle> 59 | `; 60 | 61 | type Story = StoryObj; 62 | 63 | export const Toggle: Story = Template.bind({}); 64 | Toggle.args = { 65 | checked: false, 66 | disabled: false, 67 | }; -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-toggle/dnn-toggle.tsx: -------------------------------------------------------------------------------- 1 | import { Component, h, Element, Prop, Event, EventEmitter, Watch, Host, AttachInternals, State, Listen } from "@stencil/core"; 2 | import { DnnToggleChangeEventDetail } from "./toggle-interface"; 3 | 4 | @Component({ 5 | tag: "dnn-toggle", 6 | styleUrl: "dnn-toggle.scss", 7 | shadow: true, 8 | formAssociated: true, 9 | }) 10 | export class DnnToggle { 11 | 12 | @Element() element!: HTMLDnnToggleElement; 13 | 14 | /** If 'true' the toggle is checked (on). */ 15 | @Prop({ mutable: true }) checked = false; 16 | 17 | /** If 'true' the toggle is not be interacted with. */ 18 | @Prop() disabled = false; 19 | 20 | /** The field name to use in forms. */ 21 | @Prop() name?: string; 22 | 23 | /** The value to post when used in forms. */ 24 | @Prop() value: string = "on"; 25 | 26 | /** Fires when the toggle changed */ 27 | @Event() checkChanged!: EventEmitter<DnnToggleChangeEventDetail>; 28 | 29 | @Listen("click", { capture: true }) 30 | handleClick() { 31 | this.checked = !this.checked; 32 | } 33 | 34 | @AttachInternals() internals!: ElementInternals; 35 | 36 | @Watch("checked") 37 | checkedChanged(newValue: boolean) { 38 | this.checkChanged.emit({ checked: newValue }); 39 | this.setFormValue(); 40 | } 41 | 42 | @State() focused = false; 43 | 44 | private button!: HTMLButtonElement; 45 | 46 | componentWillLoad() { 47 | this.originalChecked = this.checked; 48 | this.setFormValue(); 49 | } 50 | 51 | private originalChecked!: boolean; 52 | 53 | formResetCallback() { 54 | this.internals.setValidity({}); 55 | this.checked = this.originalChecked; 56 | } 57 | 58 | private setFormValue() { 59 | if (this.name != undefined && this.name.length > 0) { 60 | if (this.checked) { 61 | var data = new FormData(); 62 | data.append(this.name, this.value); 63 | this.internals.setFormValue(data); 64 | } 65 | else { 66 | this.internals.setFormValue(""); 67 | } 68 | } 69 | } 70 | 71 | render() { 72 | return ( 73 | <Host 74 | tabIndex={this.focused ? -1 : 0} 75 | onFocus={() => this.button.focus()} 76 | onBlur={() => this.button.blur()} 77 | > 78 | <button 79 | ref={el => this.button = el!} 80 | disabled={this.disabled} 81 | class={{ 'checked': this.checked }} 82 | onFocus={() => this.focused = true} 83 | onBlur={() => this.focused = false} 84 | > 85 | <div class="handle"></div> 86 | </button> 87 | </Host> 88 | ); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-toggle/readme.md: -------------------------------------------------------------------------------- 1 | # dnn-toggle 2 | 3 | 4 | 5 | <!-- Auto Generated Below --> 6 | 7 | 8 | ## Usage 9 | 10 | ### HTML 11 | 12 | ```html 13 | <dnn-toggle 14 | checked="true" 15 | disabled="false" 16 | name="foo" 17 | value="on" 18 | > 19 | </dnn-toggle> 20 | ``` 21 | 22 | 23 | ### JSX-TSX 24 | 25 | ```tsx 26 | <dnn-toggle 27 | checked="true" 28 | disabled="false" 29 | name="foo" 30 | value="on" 31 | > 32 | </dnn-toggle> 33 | ``` 34 | 35 | 36 | 37 | ## Properties 38 | 39 | | Property | Attribute | Description | Type | Default | 40 | | ---------- | ---------- | ----------------------------------------------- | --------------------- | ----------- | 41 | | `checked` | `checked` | If 'true' the toggle is checked (on). | `boolean` | `false` | 42 | | `disabled` | `disabled` | If 'true' the toggle is not be interacted with. | `boolean` | `false` | 43 | | `name` | `name` | The field name to use in forms. | `string \| undefined` | `undefined` | 44 | | `value` | `value` | The value to post when used in forms. | `string` | `"on"` | 45 | 46 | 47 | ## Events 48 | 49 | | Event | Description | Type | 50 | | -------------- | ----------------------------- | ----------------------------------------- | 51 | | `checkChanged` | Fires when the toggle changed | `CustomEvent<DnnToggleChangeEventDetail>` | 52 | 53 | 54 | ## CSS Custom Properties 55 | 56 | | Name | Description | 57 | | ----------------------------- | -------------------------------------- | 58 | | `--background` | Background of the toggle. | 59 | | `--background-checked` | Background of the toggle when checked. | 60 | | `--border-radius` | The radius of the background borders. | 61 | | `--handle-background` | Background of the handle. | 62 | | `--handle-background-checked` | Background of the handle when checked. | 63 | | `--handle-border-radius` | The radius of the handle. | 64 | 65 | 66 | ## Dependencies 67 | 68 | ### Used by 69 | 70 | - [dnn-example-form](../examples/dnn-example-form) 71 | 72 | ### Graph 73 | ```mermaid 74 | graph TD; 75 | dnn-example-form --> dnn-toggle 76 | style dnn-toggle fill:#f9f,stroke:#333,stroke-width:4px 77 | ``` 78 | 79 | ---------------------------------------------- 80 | 81 | *Built with [StencilJS](https://stenciljs.com/)* 82 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-toggle/toggle-interface.ts: -------------------------------------------------------------------------------- 1 | export interface DnnToggleChangeEventDetail { 2 | checked: boolean; 3 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-toggle/usage/HTML.md: -------------------------------------------------------------------------------- 1 | ```html 2 | <dnn-toggle 3 | checked="true" 4 | disabled="false" 5 | name="foo" 6 | value="on" 7 | > 8 | </dnn-toggle> 9 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-toggle/usage/JSX-TSX.md: -------------------------------------------------------------------------------- 1 | ```tsx 2 | <dnn-toggle 3 | checked="true" 4 | disabled="false" 5 | name="foo" 6 | value="on" 7 | > 8 | </dnn-toggle> 9 | ``` -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-treeview-item/dnn-treeview-item.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: flex; 3 | overflow: visible; 4 | } 5 | .expander{ 6 | width: 24px; 7 | height: 24px; 8 | button{ 9 | transition: all 150ms ease-in-out; 10 | background-color:transparent; 11 | border: none; 12 | padding: 0; 13 | margin: 0; 14 | height: 1em; 15 | display: flex; 16 | justify-content: center; 17 | align-items: center; 18 | cursor: pointer; 19 | position: relative; 20 | top: 2px; 21 | svg{ 22 | :first-child{ 23 | transition: all 150ms ease-in-out; 24 | fill: white; 25 | stroke: black 26 | } 27 | } 28 | } 29 | &.expanded{ 30 | button{ 31 | transform: rotate(45deg); 32 | svg{ 33 | :first-child{ 34 | fill: black; 35 | stroke: black; 36 | } 37 | } 38 | } 39 | } 40 | } 41 | div.item{ 42 | .item-slot{ 43 | display: flex; 44 | align-items: center; 45 | gap: 0.25em; 46 | min-height: 24px; 47 | } 48 | div.children{ 49 | overflow: hidden; 50 | height:0; 51 | transition: all 150ms ease-in-out; 52 | } 53 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-treeview-item/readme.md: -------------------------------------------------------------------------------- 1 | # dnn-treeview-item 2 | 3 | 4 | 5 | <!-- Auto Generated Below --> 6 | 7 | 8 | ## Properties 9 | 10 | | Property | Attribute | Description | Type | Default | 11 | | ---------- | ---------- | ---------------------------------------- | --------- | ------- | 12 | | `expanded` | `expanded` | Defines if the current node is expanded. | `boolean` | `false` | 13 | 14 | 15 | ## Events 16 | 17 | | Event | Description | Type | 18 | | --------------- | ------------------------------------- | ------------------- | 19 | | `userCollapsed` | Fires when the user collapses a node. | `CustomEvent<void>` | 20 | | `userExpanded` | Fires when the user expands a node. | `CustomEvent<void>` | 21 | 22 | 23 | ## Slots 24 | 25 | | Slot | Description | 26 | | ------------ | ----------------------------------- | 27 | | | The content of this node. | 28 | | `"children"` | The content nested under this node. | 29 | 30 | 31 | ## Dependencies 32 | 33 | ### Depends on 34 | 35 | - [dnn-collapsible](../dnn-collapsible) 36 | 37 | ### Graph 38 | ```mermaid 39 | graph TD; 40 | dnn-treeview-item --> dnn-collapsible 41 | style dnn-treeview-item fill:#f9f,stroke:#333,stroke-width:4px 42 | ``` 43 | 44 | ---------------------------------------------- 45 | 46 | *Built with [StencilJS](https://stenciljs.com/)* 47 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-vertical-overflow-menu/dnn-vertical-overflow-menu.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | /** 3 | * @prop --background-color: Defines the menu background color. 4 | * @prop --foreground-color: A color that contrasts with the background color. 5 | */ 6 | --background-color: var(--dnn-color-primary-contrast, white); 7 | --foreground-color: var(--dnn-color-primary, #3792ED); 8 | 9 | display: block; 10 | } 11 | 12 | .menu-container{ 13 | display: flex; 14 | justify-content: flex-start; 15 | align-items: center; 16 | background-color: var(--background-color); 17 | .menu{ 18 | margin: 0.5em; 19 | display: flex; 20 | gap: 1em; 21 | justify-content: flex-start; 22 | align-items: center; 23 | white-space: nowrap; 24 | width: 100%; 25 | } 26 | .overflow { 27 | margin-left: auto; 28 | position: relative; 29 | button{ 30 | cursor: pointer; 31 | svg{ 32 | fill: var(--foreground-color); 33 | } 34 | padding: 0; 35 | margin: 0; 36 | background-color: transparent; 37 | border: none; 38 | } 39 | .dropdown{ 40 | position:absolute; 41 | display: flex; 42 | flex-direction: column; 43 | white-space: nowrap; 44 | right: 0; 45 | transition: 100ms ease-in-out; 46 | height: 0; 47 | overflow: hidden; 48 | &.visible{ 49 | padding: 1em; 50 | gap: 0.5em; 51 | background-color: var(--background-color); 52 | box-shadow: 2px 2px 4px rgba(0,0,0,0.7); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-vertical-overflow-menu/readme.md: -------------------------------------------------------------------------------- 1 | # dnn-vertical-overflow-menu 2 | 3 | 4 | 5 | <!-- Auto Generated Below --> 6 | 7 | 8 | ## Overview 9 | 10 | A component that shows a vertical list of items as they fit. When they don't all fit, it puts the ones that don't fit into a dropdown menu. 11 | 12 | ## Slots 13 | 14 | | Slot | Description | 15 | | ------ | ------------------------------ | 16 | | `"()"` | The items to show in the menu. | 17 | 18 | 19 | ## CSS Custom Properties 20 | 21 | | Name | Description | 22 | | -------------------- | ------------------------------------------------- | 23 | | `--background-color` | Defines the menu background color. | 24 | | `--foreground-color` | A color that contrasts with the background color. | 25 | 26 | 27 | ---------------------------------------------- 28 | 29 | *Built with [StencilJS](https://stenciljs.com/)* 30 | -------------------------------------------------------------------------------- /packages/stencil-library/src/components/dnn-vertical-splitview/dnn-vertical-splitview.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | /** 3 | * @prop --left-pane-background-color: Allows customizing the left pane background-color 4 | * @prop --right-pane-background-color: Allows customizing the right pane background-color 5 | */ 6 | 7 | display: flex; 8 | align-items: stretch; 9 | margin: 0 auto; 10 | position: relative; 11 | 12 | --left-pane-background-color: transparent; 13 | --right-pane-background-color: transparent; 14 | } 15 | 16 | button{ 17 | border: none; 18 | margin:0; 19 | padding:0; 20 | cursor: ew-resize; 21 | position: absolute; 22 | height: 100%; 23 | background-color: transparent; 24 | &.transition{ 25 | transition: all 300ms ease-in-out; 26 | } 27 | } 28 | 29 | 30 | .pane{ 31 | overflow-y: auto; 32 | &.transition{ 33 | transition: all 300ms ease-in-out; 34 | } 35 | &.left{ 36 | background-color: var(--left-pane-background-color); 37 | } 38 | &.right{ 39 | background-color: var(--right-pane-background-color); 40 | flex-grow: 1; 41 | } 42 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/examples/dnn-example-form/dnn-example-form.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | } 4 | 5 | dnn-fieldset{ 6 | >.fields{ 7 | display: grid; 8 | grid-template-columns: 1fr; 9 | gap: 1rem; 10 | @media (min-width: 768px) { 11 | grid-template-columns: repeat(2, 1fr); 12 | } 13 | @media (min-width: 1024px) { 14 | grid-template-columns: repeat(3, 1fr); 15 | } 16 | label{ 17 | display: flex; 18 | flex-direction: row; 19 | align-items: center; 20 | gap: 0.5rem; 21 | &.vertical{ 22 | flex-direction: column; 23 | justify-content: flex-start; 24 | align-items: stretch; 25 | } 26 | } 27 | } 28 | } 29 | 30 | svg { 31 | width: 1em; 32 | height: 1em; 33 | } 34 | 35 | .controls{ 36 | display: flex; 37 | gap: 1rem; 38 | margin-top: 1rem; 39 | *:first-child{ 40 | margin-left: auto; 41 | } 42 | } 43 | 44 | .full-form-width{ 45 | grid-column: 1 / -1; 46 | } 47 | 48 | .filename{ 49 | display: flex; 50 | gap: 1rem; 51 | align-items: center; 52 | } 53 | 54 | .profile-pic{ 55 | display: flex; 56 | flex-direction: column; 57 | gap: 1rem; 58 | dnn-button { 59 | margin: 0 auto; 60 | } 61 | img { 62 | max-width: 100%; 63 | } 64 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/components/examples/dnn-example-form/dnn-example-form.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/web-components'; 2 | import { html } from 'lit'; 3 | import readme from "./readme.md?raw"; 4 | 5 | 6 | const meta: Meta = { 7 | title: 'Examples/Form', 8 | component: 'dnn-example-form', 9 | tags: ['autodocs'], 10 | parameters: { 11 | docs: { 12 | description: { 13 | component: readme, 14 | } 15 | } 16 | }, 17 | } 18 | export default meta; 19 | 20 | const Template = () => 21 | html` 22 | <dnn-example-form> 23 | </dnn-example-form> 24 | `; 25 | 26 | type Story = StoryObj; 27 | 28 | export const DnnFormExample: Story = Template.bind({}); -------------------------------------------------------------------------------- /packages/stencil-library/src/components/examples/dnn-example-form/readme.md: -------------------------------------------------------------------------------- 1 | # dnn-example-form 2 | 3 | 4 | 5 | <!-- Auto Generated Below --> 6 | 7 | 8 | ## Overview 9 | 10 | Do not use this component in production, it is meant for testing purposes only and is not distributed in the production package. 11 | 12 | ## Dependencies 13 | 14 | ### Depends on 15 | 16 | - [dnn-fieldset](../../dnn-fieldset) 17 | - [dnn-input](../../dnn-input) 18 | - [dnn-checkbox](../../dnn-checkbox) 19 | - [dnn-color-input](../../dnn-color-input) 20 | - [dnn-select](../../dnn-select) 21 | - [dnn-textarea](../../dnn-textarea) 22 | - [dnn-toggle](../../dnn-toggle) 23 | - [dnn-autocomplete](../../dnn-autocomplete) 24 | - [dnn-dropzone](../../dnn-dropzone) 25 | - [dnn-button](../../dnn-button) 26 | - [dnn-image-cropper](../../dnn-image-cropper) 27 | - [dnn-monaco-editor](../../dnn-monaco-editor) 28 | - [dnn-richtext](../../dnn-richtext) 29 | 30 | ### Graph 31 | ```mermaid 32 | graph TD; 33 | dnn-example-form --> dnn-fieldset 34 | dnn-example-form --> dnn-input 35 | dnn-example-form --> dnn-checkbox 36 | dnn-example-form --> dnn-color-input 37 | dnn-example-form --> dnn-select 38 | dnn-example-form --> dnn-textarea 39 | dnn-example-form --> dnn-toggle 40 | dnn-example-form --> dnn-autocomplete 41 | dnn-example-form --> dnn-dropzone 42 | dnn-example-form --> dnn-button 43 | dnn-example-form --> dnn-image-cropper 44 | dnn-example-form --> dnn-monaco-editor 45 | dnn-example-form --> dnn-richtext 46 | dnn-input --> dnn-fieldset 47 | dnn-color-input --> dnn-fieldset 48 | dnn-color-input --> dnn-modal 49 | dnn-color-input --> dnn-tabs 50 | dnn-color-input --> dnn-tab 51 | dnn-color-input --> dnn-color-picker 52 | dnn-color-input --> dnn-button 53 | dnn-button --> dnn-modal 54 | dnn-button --> dnn-button 55 | dnn-select --> dnn-fieldset 56 | dnn-textarea --> dnn-fieldset 57 | dnn-autocomplete --> dnn-fieldset 58 | dnn-image-cropper --> dnn-dropzone 59 | dnn-image-cropper --> dnn-modal 60 | style dnn-example-form fill:#f9f,stroke:#333,stroke-width:4px 61 | ``` 62 | 63 | ---------------------------------------------- 64 | 65 | *Built with [StencilJS](https://stenciljs.com/)* 66 | -------------------------------------------------------------------------------- /packages/stencil-library/src/global.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.md'; -------------------------------------------------------------------------------- /packages/stencil-library/src/index.ts: -------------------------------------------------------------------------------- 1 | export { Components, JSX } from './components'; 2 | export * from './utilities/debounce'; 3 | export * from './utilities/dnnServicesFramework'; 4 | -------------------------------------------------------------------------------- /packages/stencil-library/src/utilities/debounce.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Debounces a function call, see http://demo.nimius.net/debounce_throttle/ for explanation of debounce vs throttle. 3 | * @param debounceTime How many milliseconds to debounce for. 4 | */ 5 | export function Debounce(debounceTime: number = 500){ 6 | return function(_target: any, _key: string, descriptor: PropertyDescriptor){ 7 | 8 | let originalMethod = descriptor.value; 9 | let timer: NodeJS.Timeout; 10 | 11 | descriptor.value = function(...args: any[]){ 12 | clearTimeout(timer); 13 | return new Promise(resolve => { 14 | timer = setTimeout(() => { 15 | resolve(originalMethod.apply(this, args)); 16 | }, debounceTime); 17 | }) 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/utilities/dnnServicesFramework.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | interface Window { 3 | dnn: { 4 | //** Gets dnn variables from the page context * 5 | getVar: (key: string, defaultValue: string) => string; 6 | } 7 | } 8 | } 9 | 10 | export class DnnServicesFramework{ 11 | 12 | private _moduleId: number; 13 | 14 | /** 15 | * Initializes the serivces framework 16 | */ 17 | constructor(moduleId: number) { 18 | this._moduleId = moduleId; 19 | } 20 | 21 | getServiceRoot = (moduleName: string) => 22 | { 23 | var serviceRoot = window.top!.dnn.getVar("sf_siteRoot", "/"); 24 | serviceRoot += "API/" + moduleName + "/"; 25 | return serviceRoot; 26 | } 27 | 28 | getTabId = () => { 29 | var tabId = window.top!.dnn.getVar("sf_tabId", "-1"); 30 | return parseInt(tabId); 31 | } 32 | 33 | getModuleId = () => { 34 | return this._moduleId; 35 | } 36 | 37 | getAntiForgeryValue = () => { 38 | const el = document.querySelector("input[name=__RequestVerificationToken]") as HTMLInputElement; 39 | if (el != null){ 40 | return el.value; 41 | } 42 | else{ 43 | return null; 44 | } 45 | } 46 | 47 | getModuleHeaders = () => { 48 | var headers = new Headers(); 49 | if (this.getTabId() > -1){ 50 | headers.append("ModuleId", this._moduleId.toString()); 51 | headers.append("TabId", this.getTabId().toString()); 52 | } 53 | const afValue = this.getAntiForgeryValue(); 54 | if (afValue != null){ 55 | headers.append("RequestVerificationToken", afValue); 56 | } 57 | return headers; 58 | } 59 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/utilities/fileUtilities.ts: -------------------------------------------------------------------------------- 1 | /** Creates a file object with only a dataUrl and a filename.*/ 2 | export function dataURLtoFile(dataUrl: string, filename: string): File 3 | { 4 | // A dataUrl has metadate before the coma and the data after. 5 | let dataUrlParts = dataUrl.split(','); 6 | let mime = dataUrlParts[0]!.match(/:(.*?);/)![1]; // Extract mime type 7 | let binaryString = atob(dataUrlParts[1]); // Decode base64 (convert ascii to binary) 8 | let length = binaryString.length; 9 | 10 | // Assign binary data to typed array 11 | let u8arr = new Uint8Array(length); // Create an 8-bit unsigned array 12 | while (length > 0) { 13 | length--; 14 | u8arr[length] = binaryString.charCodeAt(length); 15 | } 16 | 17 | // Create a blob from the typed array and specify the MIME type 18 | let blob = new Blob([u8arr], { type: mime }); 19 | 20 | // Return a File object based on the Blob 21 | return new File([blob], filename, { type: mime }); 22 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/utilities/mouseUtilities.ts: -------------------------------------------------------------------------------- 1 | export function getMovementFromEvent( 2 | event: MouseEvent | TouchEvent, 3 | previousTouch?: Touch 4 | ) { 5 | let movementX = 0; 6 | let movementY = 0; 7 | if (event instanceof MouseEvent) { 8 | movementX = event.movementX; 9 | movementY = event.movementY; 10 | } 11 | if (typeof TouchEvent !== "undefined"){ 12 | if (event instanceof TouchEvent) { 13 | let touch = event.touches[0]; 14 | if (previousTouch != undefined) { 15 | movementX = touch.pageX - previousTouch.pageX; 16 | movementY = touch.pageY - previousTouch.pageY; 17 | } 18 | previousTouch = touch; 19 | } 20 | } 21 | return { movementX, movementY }; 22 | } -------------------------------------------------------------------------------- /packages/stencil-library/src/utilities/stringUtilities.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Formats a number (in bytes) to a human readable file size. 3 | */ 4 | export function getReadableFileSizeString (fileSizeInBytes: number) : string { 5 | let i = -1 6 | const byteUnits = [' kB', ' MB', ' GB', ' TB', 'PB', 'EB', 'ZB', 'YB'] 7 | if (fileSizeInBytes === 0) return `0${byteUnits[0]}` 8 | do { 9 | fileSizeInBytes = fileSizeInBytes / 1024 10 | i++ 11 | } while (fileSizeInBytes > 1024) 12 | 13 | return Math.max(fileSizeInBytes, 0.1).toFixed(1) + byteUnits[i] 14 | }; 15 | 16 | /** Takes an html encoded string and converts it to actual decoded html. */ 17 | export function decodeHtml(html: string) : string { 18 | if (html == undefined){ 19 | return ''; 20 | } 21 | 22 | const txt = document.createElement('textarea') 23 | txt.innerHTML = html 24 | return txt.value 25 | } 26 | 27 | export function generateRandomId(length: number = 16){ 28 | const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 29 | let result = ''; 30 | const charactersLength = characters.length; 31 | const array = new Uint8Array(length); 32 | 33 | window.crypto.getRandomValues(array); 34 | 35 | for (let i = 0; i < length; i++) { 36 | const randomValue = array[i]; 37 | result += characters.charAt(randomValue % charactersLength); 38 | } 39 | 40 | return result; 41 | } -------------------------------------------------------------------------------- /packages/stencil-library/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "allowUnreachableCode": false, 5 | "declaration": false, 6 | "experimentalDecorators": true, 7 | "lib": [ 8 | "dom", 9 | "es2017" 10 | ], 11 | "moduleResolution": "node", 12 | "module": "esnext", 13 | "target": "es2017", 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "jsx": "react", 17 | "jsxFactory": "h", 18 | "skipLibCheck": true, 19 | "forceConsistentCasingInFileNames": true, 20 | "strict": true 21 | }, 22 | "include": [ 23 | "src", 24 | ], 25 | "exclude": [ 26 | "node_modules", 27 | "src/**/*.stories.ts", 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /packages/stencil-library/types/raw-md.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.md?raw' { 2 | const content: string; 3 | export default content; 4 | } -------------------------------------------------------------------------------- /packages/stencil-library/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | 3 | export default defineConfig({ 4 | assetsInclude: ['**/*.md'], 5 | }); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "noImplicitAny": false, 7 | "removeComments": true, 8 | "noLib": false, 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es6", 12 | "sourceMap": true, 13 | "lib": ["es6"], 14 | "types": ["node"], 15 | "forceConsistentCasingInFileNames": true, 16 | "strict": true 17 | }, 18 | "exclude": ["node_modules", "**/*.spec.ts", "**/__tests__/**"] 19 | } --------------------------------------------------------------------------------